/*!WebUploader 0.1.5*/
layui.define(["jquery"], function(exports) {
	var jQuery = layui.jquery;
	(function($) {
		(function(root, factory) {
			var modules = {},
				_require = function(deps, callback) {
					var args, len, i;
					if(typeof deps === 'string') {
						return getModule(deps);
					} else {
						args = [];
						for(len = deps.length, i = 0; i < len; i++) {
							args.push(getModule(deps[i]));
						}
						return callback.apply(null, args);
					}
				},
				_define = function(id, deps, factory) {
					if(arguments.length === 2) {
						factory = deps;
						deps = null;
					}
					_require(deps || [], function() {
						setModule(id, factory, arguments);
					});
				},
				setModule = function(id, factory, args) {
					var module = {
							exports: factory
						},
						returned;
					if(typeof factory === 'function') {
						args.length || (args = [_require, module.exports, module]);
						returned = factory.apply(null, args);
						returned !== undefined && (module.exports = returned);
					}
					modules[id] = module.exports;
				},
				getModule = function(id) {
					var module = modules[id] || root[id];
					if(!module) {
						throw new Error('`' + id + '` is undefined');
					}
					return module;
				},
				exportsTo = function(obj) {
					var key, host, parts, part, last, ucFirst;
					ucFirst = function(str) {
						return str && (str.charAt(0).toUpperCase() + str.substr(1));
					};
					for(key in modules) {
						host = obj;
						if(!modules.hasOwnProperty(key)) {
							continue;
						}
						parts = key.split('/');
						last = ucFirst(parts.pop());
						while((part = ucFirst(parts.shift()))) {
							host[part] = host[part] || {};
							host = host[part];
						}
						host[last] = modules[key];
					}
					return obj;
				},
				makeExport = function(dollar) {
					root.__dollar = dollar;
					return exportsTo(factory(root, _define, _require));
				},
				origin;
			if(typeof module === 'object' && typeof module.exports === 'object') {
				module.exports = makeExport();
			} else if(typeof define === 'function' && define.amd) {
				define(['jquery'], makeExport);
			} else {
				origin = root.WebUploader;
				root.WebUploader = makeExport();
				root.WebUploader.noConflict = function() {
					root.WebUploader = origin;
				};
			}
		})(window, function(window, define, require) {
			define('dollar-third', [], function() {
				var $ = window.__dollar || window.jQuery || window.Zepto;
				if(!$) {
					throw new Error('jQuery or Zepto not found!');
				}
				return $;
			});
			define('dollar', ['dollar-third'], function(_) {
				return _;
			});
			define('promise-third', ['dollar'], function($) {
				return {
					Deferred: $.Deferred,
					when: $.when,
					isPromise: function(anything) {
						return anything && typeof anything.then === 'function';
					}
				};
			});
			define('promise', ['promise-third'], function(_) {
				return _;
			});
			define('base', ['dollar', 'promise'], function($, promise) {
				var noop = function() {},
					call = Function.call;

				function uncurryThis(fn) {
					return function() {
						return call.apply(fn, arguments);
					};
				}

				function bindFn(fn, context) {
					return function() {
						return fn.apply(context, arguments);
					};
				}

				function createObject(proto) {
					var f;
					if(Object.create) {
						return Object.create(proto);
					} else {
						f = function() {};
						f.prototype = proto;
						return new f();
					}
				}
				return {
					version: '0.1.5',
					$: $,
					Deferred: promise.Deferred,
					isPromise: promise.isPromise,
					when: promise.when,
					browser: (function(ua) {
						var ret = {},
							webkit = ua.match(/WebKit\/([\d.]+)/),
							chrome = ua.match(/Chrome\/([\d.]+)/) || ua.match(/CriOS\/([\d.]+)/),
							ie = ua.match(/MSIE\s([\d\.]+)/) || ua.match(/(?:trident)(?:.*rv:([\w.]+))?/i),
							firefox = ua.match(/Firefox\/([\d.]+)/),
							safari = ua.match(/Safari\/([\d.]+)/),
							opera = ua.match(/OPR\/([\d.]+)/);
						webkit && (ret.webkit = parseFloat(webkit[1]));
						chrome && (ret.chrome = parseFloat(chrome[1]));
						ie && (ret.ie = parseFloat(ie[1]));
						firefox && (ret.firefox = parseFloat(firefox[1]));
						safari && (ret.safari = parseFloat(safari[1]));
						opera && (ret.opera = parseFloat(opera[1]));
						return ret;
					})(navigator.userAgent),
					os: (function(ua) {
						var ret = {},
							android = ua.match(/(?:Android);?[\s\/]+([\d.]+)?/),
							ios = ua.match(/(?:iPad|iPod|iPhone).*OS\s([\d_]+)/);
						android && (ret.android = parseFloat(android[1]));
						ios && (ret.ios = parseFloat(ios[1].replace(/_/g, '.')));
						return ret;
					})(navigator.userAgent),
					inherits: function(Super, protos, staticProtos) {
						var child;
						if(typeof protos === 'function') {
							child = protos;
							protos = null;
						} else if(protos && protos.hasOwnProperty('constructor')) {
							child = protos.constructor;
						} else {
							child = function() {
								return Super.apply(this, arguments);
							};
						}
						$.extend(true, child, Super, staticProtos || {});
						child.__super__ = Super.prototype;
						child.prototype = createObject(Super.prototype);
						protos && $.extend(true, child.prototype, protos);
						return child;
					},
					noop: noop,
					bindFn: bindFn,
					log: (function() {
						if(window.console) {
							return bindFn(console.log, console);
						}
						return noop;
					})(),
					nextTick: (function() {
						return function(cb) {
							setTimeout(cb, 1);
						};
					})(),
					slice: uncurryThis([].slice),
					guid: (function() {
						var counter = 0;
						return function(prefix) {
							var guid = (+new Date()).toString(32),
								i = 0;
							for(; i < 5; i++) {
								guid += Math.floor(Math.random() * 65535).toString(32);
							}
							return(prefix || 'wu_') + guid + (counter++).toString(32);
						};
					})(),
					formatSize: function(size, pointLength, units) {
						var unit;
						units = units || ['B', 'K', 'M', 'G', 'TB'];
						while((unit = units.shift()) && size > 1024) {
							size = size / 1024;
						}
						return(unit === 'B' ? size : size.toFixed(pointLength || 2)) +
							unit;
					}
				};
			});
			define('mediator', ['base'], function(Base) {
				var $ = Base.$,
					slice = [].slice,
					separator = /\s+/,
					protos;

				function findHandlers(arr, name, callback, context) {
					return $.grep(arr, function(handler) {
						return handler && (!name || handler.e === name) && (!callback || handler.cb === callback || handler.cb._cb === callback) && (!context || handler.ctx === context);
					});
				}

				function eachEvent(events, callback, iterator) {
					$.each((events || '').split(separator), function(_, key) {
						iterator(key, callback);
					});
				}

				function triggerHanders(events, args) {
					var stoped = false,
						i = -1,
						len = events.length,
						handler;
					while(++i < len) {
						handler = events[i];
						if(handler.cb.apply(handler.ctx2, args) === false) {
							stoped = true;
							break;
						}
					}
					return !stoped;
				}
				protos = {
					on: function(name, callback, context) {
						var me = this,
							set;
						if(!callback) {
							return this;
						}
						set = this._events || (this._events = []);
						eachEvent(name, callback, function(name, callback) {
							var handler = {
								e: name
							};
							handler.cb = callback;
							handler.ctx = context;
							handler.ctx2 = context || me;
							handler.id = set.length;
							set.push(handler);
						});
						return this;
					},
					once: function(name, callback, context) {
						var me = this;
						if(!callback) {
							return me;
						}
						eachEvent(name, callback, function(name, callback) {
							var once = function() {
								me.off(name, once);
								return callback.apply(context || me, arguments);
							};
							once._cb = callback;
							me.on(name, once, context);
						});
						return me;
					},
					off: function(name, cb, ctx) {
						var events = this._events;
						if(!events) {
							return this;
						}
						if(!name && !cb && !ctx) {
							this._events = [];
							return this;
						}
						eachEvent(name, cb, function(name, cb) {
							$.each(findHandlers(events, name, cb, ctx), function() {
								delete events[this.id];
							});
						});
						return this;
					},
					trigger: function(type) {
						var args, events, allEvents;
						if(!this._events || !type) {
							return this;
						}
						args = slice.call(arguments, 1);
						events = findHandlers(this._events, type);
						allEvents = findHandlers(this._events, 'all');
						return triggerHanders(events, args) && triggerHanders(allEvents, arguments);
					}
				};
				return $.extend({
					installTo: function(obj) {
						return $.extend(obj, protos);
					}
				}, protos);
			});
			define('uploader', ['base', 'mediator'], function(Base, Mediator) {
				var $ = Base.$;

				function Uploader(opts) {
					this.options = $.extend(true, {}, Uploader.options, opts);
					this._init(this.options);
				}
				Uploader.options = {};
				Mediator.installTo(Uploader.prototype);
				$.each({
					upload: 'start-upload',
					stop: 'stop-upload',
					getFile: 'get-file',
					getFiles: 'get-files',
					addFile: 'add-file',
					addFiles: 'add-file',
					sort: 'sort-files',
					removeFile: 'remove-file',
					cancelFile: 'cancel-file',
					skipFile: 'skip-file',
					retry: 'retry',
					isInProgress: 'is-in-progress',
					makeThumb: 'make-thumb',
					md5File: 'md5-file',
					getDimension: 'get-dimension',
					addButton: 'add-btn',
					predictRuntimeType: 'predict-runtime-type',
					refresh: 'refresh',
					disable: 'disable',
					enable: 'enable',
					reset: 'reset'
				}, function(fn, command) {
					Uploader.prototype[fn] = function() {
						return this.request(command, arguments);
					};
				});
				$.extend(Uploader.prototype, {
					state: 'pending',
					_init: function(opts) {
						var me = this;
						me.request('init', opts, function() {
							me.state = 'ready';
							me.trigger('ready');
						});
					},
					option: function(key, val) {
						var opts = this.options;
						if(arguments.length > 1) {
							if($.isPlainObject(val) && $.isPlainObject(opts[key])) {
								$.extend(opts[key], val);
							} else {
								opts[key] = val;
							}
						} else {
							return key ? opts[key] : opts;
						}
					},
					getStats: function() {
						var stats = this.request('get-stats');
						return stats ? {
							successNum: stats.numOfSuccess,
							progressNum: stats.numOfProgress,
							cancelNum: stats.numOfCancel,
							invalidNum: stats.numOfInvalid,
							uploadFailNum: stats.numOfUploadFailed,
							queueNum: stats.numOfQueue,
							interruptNum: stats.numofInterrupt
						} : {};
					},
					trigger: function(type) {
						var args = [].slice.call(arguments, 1),
							opts = this.options,
							name = 'on' + type.substring(0, 1).toUpperCase() +
							type.substring(1);
						if(Mediator.trigger.apply(this, arguments) === false || $.isFunction(opts[name]) && opts[name].apply(this, args) === false || $.isFunction(this[name]) && this[name].apply(this, args) === false || Mediator.trigger.apply(Mediator, [this, type].concat(args)) === false) {
							return false;
						}
						return true;
					},
					destroy: function() {
						this.request('destroy', arguments);
						this.off();
					},
					request: Base.noop
				});
				Base.create = Uploader.create = function(opts) {
					return new Uploader(opts);
				};
				Base.Uploader = Uploader;
				return Uploader;
			});
			define('runtime/runtime', ['base', 'mediator'], function(Base, Mediator) {
				var $ = Base.$,
					factories = {},
					getFirstKey = function(obj) {
						for(var key in obj) {
							if(obj.hasOwnProperty(key)) {
								return key;
							}
						}
						return null;
					};

				function Runtime(options) {
					this.options = $.extend({
						container: document.body
					}, options);
					this.uid = Base.guid('rt_');
				}
				$.extend(Runtime.prototype, {
					getContainer: function() {
						var opts = this.options,
							parent, container;
						if(this._container) {
							return this._container;
						}
						parent = $(opts.container || document.body);
						container = $(document.createElement('div'));
						container.attr('id', 'rt_' + this.uid);
						container.css({
							position: 'absolute',
							top: '0px',
							left: '0px',
							width: '1px',
							height: '1px',
							overflow: 'hidden'
						});
						parent.append(container);
						parent.addClass('webuploader-container');
						this._container = container;
						this._parent = parent;
						return container;
					},
					init: Base.noop,
					exec: Base.noop,
					destroy: function() {
						this._container && this._container.remove();
						this._parent && this._parent.removeClass('webuploader-container');
						this.off();
					}
				});
				Runtime.orders = 'html5,flash';
				Runtime.addRuntime = function(type, factory) {
					factories[type] = factory;
				};
				Runtime.hasRuntime = function(type) {
					return !!(type ? factories[type] : getFirstKey(factories));
				};
				Runtime.create = function(opts, orders) {
					var type, runtime;
					orders = orders || Runtime.orders;
					$.each(orders.split(/\s*,\s*/g), function() {
						if(factories[this]) {
							type = this;
							return false;
						}
					});
					type = type || getFirstKey(factories);
					if(!type) {
						throw new Error('Runtime Error');
					}
					runtime = new factories[type](opts);
					return runtime;
				};
				Mediator.installTo(Runtime.prototype);
				return Runtime;
			});
			define('runtime/client', ['base', 'mediator', 'runtime/runtime'], function(Base, Mediator, Runtime) {
				var cache;
				cache = (function() {
					var obj = {};
					return {
						add: function(runtime) {
							obj[runtime.uid] = runtime;
						},
						get: function(ruid, standalone) {
							var i;
							if(ruid) {
								return obj[ruid];
							}
							for(i in obj) {
								if(standalone && obj[i].__standalone) {
									continue;
								}
								return obj[i];
							}
							return null;
						},
						remove: function(runtime) {
							delete obj[runtime.uid];
						}
					};
				})();

				function RuntimeClient(component, standalone) {
					var deferred = Base.Deferred(),
						runtime;
					this.uid = Base.guid('client_');
					this.runtimeReady = function(cb) {
						return deferred.done(cb);
					};
					this.connectRuntime = function(opts, cb) {
						if(runtime) {
							throw new Error('already connected!');
						}
						deferred.done(cb);
						if(typeof opts === 'string' && cache.get(opts)) {
							runtime = cache.get(opts);
						}
						runtime = runtime || cache.get(null, standalone);
						if(!runtime) {
							runtime = Runtime.create(opts, opts.runtimeOrder);
							runtime.__promise = deferred.promise();
							runtime.once('ready', deferred.resolve);
							runtime.init();
							cache.add(runtime);
							runtime.__client = 1;
						} else {
							Base.$.extend(runtime.options, opts);
							runtime.__promise.then(deferred.resolve);
							runtime.__client++;
						}
						standalone && (runtime.__standalone = standalone);
						return runtime;
					};
					this.getRuntime = function() {
						return runtime;
					};
					this.disconnectRuntime = function() {
						if(!runtime) {
							return;
						}
						runtime.__client--;
						if(runtime.__client <= 0) {
							cache.remove(runtime);
							delete runtime.__promise;
							runtime.destroy();
						}
						runtime = null;
					};
					this.exec = function() {
						if(!runtime) {
							return;
						}
						var args = Base.slice(arguments);
						component && args.unshift(component);
						return runtime.exec.apply(this, args);
					};
					this.getRuid = function() {
						return runtime && runtime.uid;
					};
					this.destroy = (function(destroy) {
						return function() {
							destroy && destroy.apply(this, arguments);
							this.trigger('destroy');
							this.off();
							this.exec('destroy');
							this.disconnectRuntime();
						};
					})(this.destroy);
				}
				Mediator.installTo(RuntimeClient.prototype);
				return RuntimeClient;
			});
			define('lib/dnd', ['base', 'mediator', 'runtime/client'], function(Base, Mediator, RuntimeClent) {
				var $ = Base.$;

				function DragAndDrop(opts) {
					opts = this.options = $.extend({}, DragAndDrop.options, opts);
					opts.container = $(opts.container);
					if(!opts.container.length) {
						return;
					}
					RuntimeClent.call(this, 'DragAndDrop');
				}
				DragAndDrop.options = {
					accept: null,
					disableGlobalDnd: false
				};
				Base.inherits(RuntimeClent, {
					constructor: DragAndDrop,
					init: function() {
						var me = this;
						me.connectRuntime(me.options, function() {
							me.exec('init');
							me.trigger('ready');
						});
					}
				});
				Mediator.installTo(DragAndDrop.prototype);
				return DragAndDrop;
			});
			define('widgets/widget', ['base', 'uploader'], function(Base, Uploader) {
				var $ = Base.$,
					_init = Uploader.prototype._init,
					_destroy = Uploader.prototype.destroy,
					IGNORE = {},
					widgetClass = [];

				function isArrayLike(obj) {
					if(!obj) {
						return false;
					}
					var length = obj.length,
						type = $.type(obj);
					if(obj.nodeType === 1 && length) {
						return true;
					}
					return type === 'array' || type !== 'function' && type !== 'string' && (length === 0 || typeof length === 'number' && length > 0 && (length - 1) in obj);
				}

				function Widget(uploader) {
					this.owner = uploader;
					this.options = uploader.options;
				}
				$.extend(Widget.prototype, {
					init: Base.noop,
					invoke: function(apiName, args) {
						var map = this.responseMap;
						if(!map || !(apiName in map) || !(map[apiName] in this) || !$.isFunction(this[map[apiName]])) {
							return IGNORE;
						}
						return this[map[apiName]].apply(this, args);
					},
					request: function() {
						return this.owner.request.apply(this.owner, arguments);
					}
				});
				$.extend(Uploader.prototype, {
					_init: function() {
						var me = this,
							widgets = me._widgets = [],
							deactives = me.options.disableWidgets || '';
						$.each(widgetClass, function(_, klass) {
							(!deactives || !~deactives.indexOf(klass._name)) && widgets.push(new klass(me));
						});
						return _init.apply(me, arguments);
					},
					request: function(apiName, args, callback) {
						var i = 0,
							widgets = this._widgets,
							len = widgets && widgets.length,
							rlts = [],
							dfds = [],
							widget, rlt, promise, key;
						args = isArrayLike(args) ? args : [args];
						for(; i < len; i++) {
							widget = widgets[i];
							rlt = widget.invoke(apiName, args);
							if(rlt !== IGNORE) {
								if(Base.isPromise(rlt)) {
									dfds.push(rlt);
								} else {
									rlts.push(rlt);
								}
							}
						}
						if(callback || dfds.length) {
							promise = Base.when.apply(Base, dfds);
							key = promise.pipe ? 'pipe' : 'then';
							return promise[key](function() {
								var deferred = Base.Deferred(),
									args = arguments;
								if(args.length === 1) {
									args = args[0];
								}
								setTimeout(function() {
									deferred.resolve(args);
								}, 1);
								return deferred.promise();
							})[callback ? key : 'done'](callback || Base.noop);
						} else {
							return rlts[0];
						}
					},
					destroy: function() {
						_destroy.apply(this, arguments);
						this._widgets = null;
					}
				});
				Uploader.register = Widget.register = function(responseMap, widgetProto) {
					var map = {
							init: 'init',
							destroy: 'destroy',
							name: 'anonymous'
						},
						klass;
					if(arguments.length === 1) {
						widgetProto = responseMap;
						$.each(widgetProto, function(key) {
							if(key[0] === '_' || key === 'name') {
								key === 'name' && (map.name = widgetProto.name);
								return;
							}
							map[key.replace(/[A-Z]/g, '-$&').toLowerCase()] = key;
						});
					} else {
						map = $.extend(map, responseMap);
					}
					widgetProto.responseMap = map;
					klass = Base.inherits(Widget, widgetProto);
					klass._name = map.name;
					widgetClass.push(klass);
					return klass;
				};
				Uploader.unRegister = Widget.unRegister = function(name) {
					if(!name || name === 'anonymous') {
						return;
					}
					for(var i = widgetClass.length; i--;) {
						if(widgetClass[i]._name === name) {
							widgetClass.splice(i, 1)
						}
					}
				};
				return Widget;
			});
			define('widgets/filednd', ['base', 'uploader', 'lib/dnd', 'widgets/widget'], function(Base, Uploader, Dnd) {
				var $ = Base.$;
				Uploader.options.dnd = '';
				return Uploader.register({
					name: 'dnd',
					init: function(opts) {
						if(!opts.dnd || this.request('predict-runtime-type') !== 'html5') {
							return;
						}
						var me = this,
							deferred = Base.Deferred(),
							options = $.extend({}, {
								disableGlobalDnd: opts.disableGlobalDnd,
								container: opts.dnd,
								accept: opts.accept
							}),
							dnd;
						this.dnd = dnd = new Dnd(options);
						dnd.once('ready', deferred.resolve);
						dnd.on('drop', function(files) {
							me.request('add-file', [files]);
						});
						dnd.on('accept', function(items) {
							return me.owner.trigger('dndAccept', items);
						});
						dnd.init();
						return deferred.promise();
					},
					destroy: function() {
						this.dnd && this.dnd.destroy();
					}
				});
			});
			define('lib/filepaste', ['base', 'mediator', 'runtime/client'], function(Base, Mediator, RuntimeClent) {
				var $ = Base.$;

				function FilePaste(opts) {
					opts = this.options = $.extend({}, opts);
					opts.container = $(opts.container || document.body);
					RuntimeClent.call(this, 'FilePaste');
				}
				Base.inherits(RuntimeClent, {
					constructor: FilePaste,
					init: function() {
						var me = this;
						me.connectRuntime(me.options, function() {
							me.exec('init');
							me.trigger('ready');
						});
					}
				});
				Mediator.installTo(FilePaste.prototype);
				return FilePaste;
			});
			define('widgets/filepaste', ['base', 'uploader', 'lib/filepaste', 'widgets/widget'], function(Base, Uploader, FilePaste) {
				var $ = Base.$;
				return Uploader.register({
					name: 'paste',
					init: function(opts) {
						if(!opts.paste || this.request('predict-runtime-type') !== 'html5') {
							return;
						}
						var me = this,
							deferred = Base.Deferred(),
							options = $.extend({}, {
								container: opts.paste,
								accept: opts.accept
							}),
							paste;
						this.paste = paste = new FilePaste(options);
						paste.once('ready', deferred.resolve);
						paste.on('paste', function(files) {
							me.owner.request('add-file', [files]);
						});
						paste.init();
						return deferred.promise();
					},
					destroy: function() {
						this.paste && this.paste.destroy();
					}
				});
			});
			define('lib/blob', ['base', 'runtime/client'], function(Base, RuntimeClient) {
				function Blob(ruid, source) {
					var me = this;
					me.source = source;
					me.ruid = ruid;
					this.size = source.size || 0;
					if(!source.type && this.ext && ~'jpg,jpeg,png,gif,bmp'.indexOf(this.ext)) {
						this.type = 'image/' + (this.ext === 'jpg' ? 'jpeg' : this.ext);
					} else {
						this.type = source.type || 'application/octet-stream';
					}
					RuntimeClient.call(me, 'Blob');
					this.uid = source.uid || this.uid;
					if(ruid) {
						me.connectRuntime(ruid);
					}
				}
				Base.inherits(RuntimeClient, {
					constructor: Blob,
					slice: function(start, end) {
						return this.exec('slice', start, end);
					},
					getSource: function() {
						return this.source;
					}
				});
				return Blob;
			});
			define('lib/file', ['base', 'lib/blob'], function(Base, Blob) {
				var uid = 1,
					rExt = /\.([^.]+)$/;

				function File(ruid, file) {
					var ext;
					this.name = file.name || ('untitled' + uid++);
					ext = rExt.exec(file.name) ? RegExp.$1.toLowerCase() : '';
					if(!ext && file.type) {
						ext = /\/(jpg|jpeg|png|gif|bmp)$/i.exec(file.type) ? RegExp.$1.toLowerCase() : '';
						this.name += '.' + ext;
					}
					this.ext = ext;
					this.lastModifiedDate = file.lastModifiedDate || (new Date()).toLocaleString();
					Blob.apply(this, arguments);
				}
				return Base.inherits(Blob, File);
			});
			define('lib/filepicker', ['base', 'runtime/client', 'lib/file'], function(Base, RuntimeClent, File) {
				var $ = Base.$;

				function FilePicker(opts) {
					opts = this.options = $.extend({}, FilePicker.options, opts);
					opts.container = $(opts.id);
					if(!opts.container.length) {
						throw new Error('鎸夐挳鎸囧畾閿欒');
					}
					opts.innerHTML = opts.innerHTML || opts.label || opts.container.html() || '';
					opts.button = $(opts.button || document.createElement('div'));
					opts.button.html(opts.innerHTML);
					opts.container.html(opts.button);
					RuntimeClent.call(this, 'FilePicker', true);
				}
				FilePicker.options = {
					button: null,
					container: null,
					label: null,
					innerHTML: null,
					multiple: true,
					accept: null,
					name: 'file'
				};
				Base.inherits(RuntimeClent, {
					constructor: FilePicker,
					init: function() {
						var me = this,
							opts = me.options,
							button = opts.button;
						button.addClass('webuploader-pick');
						me.on('all', function(type) {
							var files;
							switch(type) {
								case 'mouseenter':
									button.addClass('webuploader-pick-hover');
									break;
								case 'mouseleave':
									button.removeClass('webuploader-pick-hover');
									break;
								case 'change':
									files = me.exec('getFiles');
									me.trigger('select', $.map(files, function(file) {
										file = new File(me.getRuid(), file);
										file._refer = opts.container;
										return file;
									}), opts.container);
									break;
							}
						});
						me.connectRuntime(opts, function() {
							me.refresh();
							me.exec('init', opts);
							me.trigger('ready');
						});
						this._resizeHandler = Base.bindFn(this.refresh, this);
						$(window).on('resize', this._resizeHandler);
					},
					refresh: function() {
						var shimContainer = this.getRuntime().getContainer(),
							button = this.options.button,
							width = button.outerWidth ? button.outerWidth() : button.width(),
							height = button.outerHeight ? button.outerHeight() : button.height(),
							pos = button.offset();
						width && height && shimContainer.css({
							bottom: 'auto',
							right: 'auto',
							width: width + 'px',
							height: height + 'px'
						}).offset(pos);
					},
					enable: function() {
						var btn = this.options.button;
						btn.removeClass('webuploader-pick-disable');
						this.refresh();
					},
					disable: function() {
						var btn = this.options.button;
						this.getRuntime().getContainer().css({
							top: '-99999px'
						});
						btn.addClass('webuploader-pick-disable');
					},
					destroy: function() {
						var btn = this.options.button;
						$(window).off('resize', this._resizeHandler);
						btn.removeClass('webuploader-pick-disable webuploader-pick-hover ' +
							'webuploader-pick');
					}
				});
				return FilePicker;
			});
			define('widgets/filepicker', ['base', 'uploader', 'lib/filepicker', 'widgets/widget'], function(Base, Uploader, FilePicker) {
				var $ = Base.$;
				$.extend(Uploader.options, {
					pick: null,
					accept: null
				});
				return Uploader.register({
					name: 'picker',
					init: function(opts) {
						this.pickers = [];
						return opts.pick && this.addBtn(opts.pick);
					},
					refresh: function() {
						$.each(this.pickers, function() {
							this.refresh();
						});
					},
					addBtn: function(pick) {
						var me = this,
							opts = me.options,
							accept = opts.accept,
							promises = [];
						if(!pick) {
							return;
						}
						$.isPlainObject(pick) || (pick = {
							id: pick
						});
						$(pick.id).each(function() {
							var options, picker, deferred;
							deferred = Base.Deferred();
							options = $.extend({}, pick, {
								accept: $.isPlainObject(accept) ? [accept] : accept,
								swf: opts.swf,
								runtimeOrder: opts.runtimeOrder,
								id: this
							});
							picker = new FilePicker(options);
							picker.once('ready', deferred.resolve);
							picker.on('select', function(files) {
								me.owner.request('add-file', [files]);
							});
							picker.init();
							me.pickers.push(picker);
							promises.push(deferred.promise());
						});
						return Base.when.apply(Base, promises);
					},
					disable: function() {
						$.each(this.pickers, function() {
							this.disable();
						});
					},
					enable: function() {
						$.each(this.pickers, function() {
							this.enable();
						});
					},
					destroy: function() {
						$.each(this.pickers, function() {
							this.destroy();
						});
						this.pickers = null;
					}
				});
			});
			define('lib/image', ['base', 'runtime/client', 'lib/blob'], function(Base, RuntimeClient, Blob) {
				var $ = Base.$;

				function Image(opts) {
					this.options = $.extend({}, Image.options, opts);
					RuntimeClient.call(this, 'Image');
					this.on('load', function() {
						this._info = this.exec('info');
						this._meta = this.exec('meta');
					});
				}
				Image.options = {
					quality: 90,
					crop: false,
					preserveHeaders: false,
					allowMagnify: false
				};
				Base.inherits(RuntimeClient, {
					constructor: Image,
					info: function(val) {
						if(val) {
							this._info = val;
							return this;
						}
						return this._info;
					},
					meta: function(val) {
						if(val) {
							this._meta = val;
							return this;
						}
						return this._meta;
					},
					loadFromBlob: function(blob) {
						var me = this,
							ruid = blob.getRuid();
						this.connectRuntime(ruid, function() {
							me.exec('init', me.options);
							me.exec('loadFromBlob', blob);
						});
					},
					resize: function() {
						var args = Base.slice(arguments);
						return this.exec.apply(this, ['resize'].concat(args));
					},
					crop: function() {
						var args = Base.slice(arguments);
						return this.exec.apply(this, ['crop'].concat(args));
					},
					getAsDataUrl: function(type) {
						return this.exec('getAsDataUrl', type);
					},
					getAsBlob: function(type) {
						var blob = this.exec('getAsBlob', type);
						return new Blob(this.getRuid(), blob);
					}
				});
				return Image;
			});
			define('widgets/image', ['base', 'uploader', 'lib/image', 'widgets/widget'], function(Base, Uploader, Image) {
				var $ = Base.$,
					throttle;
				throttle = (function(max) {
					var occupied = 0,
						waiting = [],
						tick = function() {
							var item;
							while(waiting.length && occupied < max) {
								item = waiting.shift();
								occupied += item[0];
								item[1]();
							}
						};
					return function(emiter, size, cb) {
						waiting.push([size, cb]);
						emiter.once('destroy', function() {
							occupied -= size;
							setTimeout(tick, 1);
						});
						setTimeout(tick, 1);
					};
				})(5 * 1024 * 1024);
				$.extend(Uploader.options, {
					thumb: {
						width: 110,
						height: 110,
						quality: 70,
						allowMagnify: true,
						crop: true,
						preserveHeaders: false,
						type: 'image/jpeg'
					},
					compress: {
						width: 1600,
						height: 1600,
						quality: 90,
						allowMagnify: false,
						crop: false,
						preserveHeaders: true
					}
				});
				return Uploader.register({
					name: 'image',
					makeThumb: function(file, cb, width, height) {
						var opts, image;
						file = this.request('get-file', file);
						if(!file.type.match(/^image/)) {
							cb(true);
							return;
						}
						opts = $.extend({}, this.options.thumb);
						if($.isPlainObject(width)) {
							opts = $.extend(opts, width);
							width = null;
						}
						width = width || opts.width;
						height = height || opts.height;
						image = new Image(opts);
						image.once('load', function() {
							file._info = file._info || image.info();
							file._meta = file._meta || image.meta();
							if(width <= 1 && width > 0) {
								width = file._info.width * width;
							}
							if(height <= 1 && height > 0) {
								height = file._info.height * height;
							}
							image.resize(width, height);
						});
						image.once('complete', function() {
							cb(false, image.getAsDataUrl(opts.type));
							image.destroy();
						});
						image.once('error', function(reason) {
							cb(reason || true);
							image.destroy();
						});
						throttle(image, file.source.size, function() {
							file._info && image.info(file._info);
							file._meta && image.meta(file._meta);
							image.loadFromBlob(file.source);
						});
					},
					beforeSendFile: function(file) {
						var opts = this.options.compress || this.options.resize,
							compressSize = opts && opts.compressSize || 0,
							noCompressIfLarger = opts && opts.noCompressIfLarger || false,
							image, deferred;
						file = this.request('get-file', file);
						if(!opts || !~'image/jpeg,image/jpg'.indexOf(file.type) || file.size < compressSize || file._compressed) {
							return;
						}
						opts = $.extend({}, opts);
						deferred = Base.Deferred();
						image = new Image(opts);
						deferred.always(function() {
							image.destroy();
							image = null;
						});
						image.once('error', deferred.reject);
						image.once('load', function() {
							var width = opts.width,
								height = opts.height;
							file._info = file._info || image.info();
							file._meta = file._meta || image.meta();
							if(width <= 1 && width > 0) {
								width = file._info.width * width;
							}
							if(height <= 1 && height > 0) {
								height = file._info.height * height;
							}
							image.resize(width, height);
						});
						image.once('complete', function() {
							var blob, size;
							try {
								blob = image.getAsBlob(opts.type);
								size = file.size;
								if(!noCompressIfLarger || blob.size < size) {
									file.source = blob;
									file.size = blob.size;
									file.trigger('resize', blob.size, size);
								}
								file._compressed = true;
								deferred.resolve();
							} catch(e) {
								deferred.resolve();
							}
						});
						file._info && image.info(file._info);
						file._meta && image.meta(file._meta);
						image.loadFromBlob(file.source);
						return deferred.promise();
					}
				});
			});
			define('file', ['base', 'mediator'], function(Base, Mediator) {
				var $ = Base.$,
					idPrefix = 'WU_FILE_',
					idSuffix = 0,
					rExt = /\.([^.]+)$/,
					statusMap = {};

				function gid() {
					return idPrefix + idSuffix++;
				}

				function WUFile(source) {
					this.name = source.name || 'Untitled';
					this.size = source.size || 0;
					this.type = source.type || 'application/octet-stream';
					this.lastModifiedDate = source.lastModifiedDate || (new Date() * 1);
					this.id = gid();
					this.ext = rExt.exec(this.name) ? RegExp.$1 : '';
					this.statusText = '';
					statusMap[this.id] = WUFile.Status.INITED;
					this.source = source;
					this.loaded = 0;
					this.on('error', function(msg) {
						this.setStatus(WUFile.Status.ERROR, msg);
					});
				}
				$.extend(WUFile.prototype, {
					setStatus: function(status, text) {
						var prevStatus = statusMap[this.id];
						typeof text !== 'undefined' && (this.statusText = text);
						if(status !== prevStatus) {
							statusMap[this.id] = status;
							this.trigger('statuschange', status, prevStatus);
						}
					},
					getStatus: function() {
						return statusMap[this.id];
					},
					getSource: function() {
						return this.source;
					},
					destroy: function() {
						this.off();
						delete statusMap[this.id];
					}
				});
				Mediator.installTo(WUFile.prototype);
				WUFile.Status = {
					INITED: 'inited',
					QUEUED: 'queued',
					PROGRESS: 'progress',
					ERROR: 'error',
					COMPLETE: 'complete',
					CANCELLED: 'cancelled',
					INTERRUPT: 'interrupt',
					INVALID: 'invalid'
				};
				return WUFile;
			});
			define('queue', ['base', 'mediator', 'file'], function(Base, Mediator, WUFile) {
				var $ = Base.$,
					STATUS = WUFile.Status;

				function Queue() {
					this.stats = {
						numOfQueue: 0,
						numOfSuccess: 0,
						numOfCancel: 0,
						numOfProgress: 0,
						numOfUploadFailed: 0,
						numOfInvalid: 0,
						numofDeleted: 0,
						numofInterrupt: 0
					};
					this._queue = [];
					this._map = {};
				}
				$.extend(Queue.prototype, {
					append: function(file) {
						this._queue.push(file);
						this._fileAdded(file);
						return this;
					},
					prepend: function(file) {
						this._queue.unshift(file);
						this._fileAdded(file);
						return this;
					},
					getFile: function(fileId) {
						if(typeof fileId !== 'string') {
							return fileId;
						}
						return this._map[fileId];
					},
					fetch: function(status) {
						var len = this._queue.length,
							i, file;
						status = status || STATUS.QUEUED;
						for(i = 0; i < len; i++) {
							file = this._queue[i];
							if(status === file.getStatus()) {
								return file;
							}
						}
						return null;
					},
					sort: function(fn) {
						if(typeof fn === 'function') {
							this._queue.sort(fn);
						}
					},
					getFiles: function() {
						var sts = [].slice.call(arguments, 0),
							ret = [],
							i = 0,
							len = this._queue.length,
							file;
						for(; i < len; i++) {
							file = this._queue[i];
							if(sts.length && !~$.inArray(file.getStatus(), sts)) {
								continue;
							}
							ret.push(file);
						}
						return ret;
					},
					removeFile: function(file) {
						var me = this,
							existing = this._map[file.id];
						if(existing) {
							delete this._map[file.id];
							file.destroy();
							this.stats.numofDeleted++;
						}
					},
					_fileAdded: function(file) {
						var me = this,
							existing = this._map[file.id];
						if(!existing) {
							this._map[file.id] = file;
							file.on('statuschange', function(cur, pre) {
								me._onFileStatusChange(cur, pre);
							});
						}
					},
					_onFileStatusChange: function(curStatus, preStatus) {
						var stats = this.stats;
						switch(preStatus) {
							case STATUS.PROGRESS:
								stats.numOfProgress--;
								break;
							case STATUS.QUEUED:
								stats.numOfQueue--;
								break;
							case STATUS.ERROR:
								stats.numOfUploadFailed--;
								break;
							case STATUS.INVALID:
								stats.numOfInvalid--;
								break;
							case STATUS.INTERRUPT:
								stats.numofInterrupt--;
								break;
						}
						switch(curStatus) {
							case STATUS.QUEUED:
								stats.numOfQueue++;
								break;
							case STATUS.PROGRESS:
								stats.numOfProgress++;
								break;
							case STATUS.ERROR:
								stats.numOfUploadFailed++;
								break;
							case STATUS.COMPLETE:
								stats.numOfSuccess++;
								break;
							case STATUS.CANCELLED:
								stats.numOfCancel++;
								break;
							case STATUS.INVALID:
								stats.numOfInvalid++;
								break;
							case STATUS.INTERRUPT:
								stats.numofInterrupt++;
								break;
						}
					}
				});
				Mediator.installTo(Queue.prototype);
				return Queue;
			});
			define('widgets/queue', ['base', 'uploader', 'queue', 'file', 'lib/file', 'runtime/client', 'widgets/widget'], function(Base, Uploader, Queue, WUFile, File, RuntimeClient) {
				var $ = Base.$,
					rExt = /\.\w+$/,
					Status = WUFile.Status;
				return Uploader.register({
					name: 'queue',
					init: function(opts) {
						var me = this,
							deferred, len, i, item, arr, accept, runtime;
						if($.isPlainObject(opts.accept)) {
							opts.accept = [opts.accept];
						}
						if(opts.accept) {
							arr = [];
							for(i = 0, len = opts.accept.length; i < len; i++) {
								item = opts.accept[i].extensions;
								item && arr.push(item);
							}
							if(arr.length) {
								accept = '\\.' + arr.join(',').replace(/,/g, '$|\\.').replace(/\*/g, '.*') + '$';
							}
							me.accept = new RegExp(accept, 'i');
						}
						me.queue = new Queue();
						me.stats = me.queue.stats;
						if(this.request('predict-runtime-type') !== 'html5') {
							return;
						}
						deferred = Base.Deferred();
						this.placeholder = runtime = new RuntimeClient('Placeholder');
						runtime.connectRuntime({
							runtimeOrder: 'html5'
						}, function() {
							me._ruid = runtime.getRuid();
							deferred.resolve();
						});
						return deferred.promise();
					},
					_wrapFile: function(file) {
						if(!(file instanceof WUFile)) {
							if(!(file instanceof File)) {
								if(!this._ruid) {
									throw new Error('Can\'t add external files.');
								}
								file = new File(this._ruid, file);
							}
							file = new WUFile(file);
						}
						return file;
					},
					acceptFile: function(file) {
						var invalid = !file || !file.size || this.accept && rExt.exec(file.name) && !this.accept.test(file.name);
						return !invalid;
					},
					_addFile: function(file) {
						var me = this;
						file = me._wrapFile(file);
						if(!me.owner.trigger('beforeFileQueued', file)) {
							return;
						}
						if(!me.acceptFile(file)) {
							me.owner.trigger('error', 'Q_TYPE_DENIED', file);
							return;
						}
						me.queue.append(file);
						me.owner.trigger('fileQueued', file);
						return file;
					},
					getFile: function(fileId) {
						return this.queue.getFile(fileId);
					},
					addFile: function(files) {
						var me = this;
						if(!files.length) {
							files = [files];
						}
						files = $.map(files, function(file) {
							return me._addFile(file);
						});
						me.owner.trigger('filesQueued', files);
						if(me.options.auto) {
							setTimeout(function() {
								me.request('start-upload');
							}, 20);
						}
					},
					getStats: function() {
						return this.stats;
					},
					removeFile: function(file, remove) {
						var me = this;
						file = file.id ? file : me.queue.getFile(file);
						this.request('cancel-file', file);
						if(remove) {
							this.queue.removeFile(file);
						}
					},
					getFiles: function() {
						return this.queue.getFiles.apply(this.queue, arguments);
					},
					fetchFile: function() {
						return this.queue.fetch.apply(this.queue, arguments);
					},
					retry: function(file, noForceStart) {
						var me = this,
							files, i, len;
						if(file) {
							file = file.id ? file : me.queue.getFile(file);
							file.setStatus(Status.QUEUED);
							noForceStart || me.request('start-upload');
							return;
						}
						files = me.queue.getFiles(Status.ERROR);
						i = 0;
						len = files.length;
						for(; i < len; i++) {
							file = files[i];
							file.setStatus(Status.QUEUED);
						}
						me.request('start-upload');
					},
					sortFiles: function() {
						return this.queue.sort.apply(this.queue, arguments);
					},
					reset: function() {
						this.owner.trigger('reset');
						this.queue = new Queue();
						this.stats = this.queue.stats;
					},
					destroy: function() {
						this.reset();
						this.placeholder && this.placeholder.destroy();
					}
				});
			});
			define('widgets/runtime', ['uploader', 'runtime/runtime', 'widgets/widget'], function(Uploader, Runtime) {
				Uploader.support = function() {
					return Runtime.hasRuntime.apply(Runtime, arguments);
				};
				return Uploader.register({
					name: 'runtime',
					init: function() {
						if(!this.predictRuntimeType()) {
							throw Error('Runtime Error');
						}
					},
					predictRuntimeType: function() {
						var orders = this.options.runtimeOrder || Runtime.orders,
							type = this.type,
							i, len;
						if(!type) {
							orders = orders.split(/\s*,\s*/g);
							for(i = 0, len = orders.length; i < len; i++) {
								if(Runtime.hasRuntime(orders[i])) {
									this.type = type = orders[i];
									break;
								}
							}
						}
						return type;
					}
				});
			});
			define('lib/transport', ['base', 'runtime/client', 'mediator'], function(Base, RuntimeClient, Mediator) {
				var $ = Base.$;

				function Transport(opts) {
					var me = this;
					opts = me.options = $.extend(true, {}, Transport.options, opts || {});
					RuntimeClient.call(this, 'Transport');
					this._blob = null;
					this._formData = opts.formData || {};
					this._headers = opts.headers || {};
					this.on('progress', this._timeout);
					this.on('load error', function() {
						me.trigger('progress', 1);
						clearTimeout(me._timer);
					});
				}
				Transport.options = {
					server: '',
					method: 'POST',
					withCredentials: false,
					fileVal: 'file',
					timeout: 2 * 60 * 1000,
					formData: {},
					headers: {},
					sendAsBinary: false
				};
				$.extend(Transport.prototype, {
					appendBlob: function(key, blob, filename) {
						var me = this,
							opts = me.options;
						if(me.getRuid()) {
							me.disconnectRuntime();
						}
						me.connectRuntime(blob.ruid, function() {
							me.exec('init');
						});
						me._blob = blob;
						opts.fileVal = key || opts.fileVal;
						opts.filename = filename || opts.filename;
					},
					append: function(key, value) {
						if(typeof key === 'object') {
							$.extend(this._formData, key);
						} else {
							this._formData[key] = value;
						}
					},
					setRequestHeader: function(key, value) {
						if(typeof key === 'object') {
							$.extend(this._headers, key);
						} else {
							this._headers[key] = value;
						}
					},
					send: function(method) {
						this.exec('send', method);
						this._timeout();
					},
					abort: function() {
						clearTimeout(this._timer);
						return this.exec('abort');
					},
					destroy: function() {
						this.trigger('destroy');
						this.off();
						this.exec('destroy');
						this.disconnectRuntime();
					},
					getResponse: function() {
						return this.exec('getResponse');
					},
					getResponseAsJson: function() {
						return this.exec('getResponseAsJson');
					},
					getStatus: function() {
						return this.exec('getStatus');
					},
					_timeout: function() {
						var me = this,
							duration = me.options.timeout;
						if(!duration) {
							return;
						}
						clearTimeout(me._timer);
						me._timer = setTimeout(function() {
							me.abort();
							me.trigger('error', 'timeout');
						}, duration);
					}
				});
				Mediator.installTo(Transport.prototype);
				return Transport;
			});
			define('widgets/upload', ['base', 'uploader', 'file', 'lib/transport', 'widgets/widget'], function(Base, Uploader, WUFile, Transport) {
				var $ = Base.$,
					isPromise = Base.isPromise,
					Status = WUFile.Status;
				$.extend(Uploader.options, {
					prepareNextFile: false,
					chunked: false,
					chunkSize: 5 * 1024 * 1024,
					chunkRetry: 2,
					threads: 3,
					formData: {}
				});

				function CuteFile(file, chunkSize) {
					var pending = [],
						blob = file.source,
						total = blob.size,
						chunks = chunkSize ? Math.ceil(total / chunkSize) : 1,
						start = 0,
						index = 0,
						len, api;
					api = {
						file: file,
						has: function() {
							return !!pending.length;
						},
						shift: function() {
							return pending.shift();
						},
						unshift: function(block) {
							pending.unshift(block);
						}
					};
					while(index < chunks) {
						len = Math.min(chunkSize, total - start);
						pending.push({
							file: file,
							start: start,
							end: chunkSize ? (start + len) : total,
							total: total,
							chunks: chunks,
							chunk: index++,
							cuted: api
						});
						start += len;
					}
					file.blocks = pending.concat();
					file.remaning = pending.length;
					return api;
				}
				Uploader.register({
					name: 'upload',
					init: function() {
						var owner = this.owner,
							me = this;
						this.runing = false;
						this.progress = false;
						owner.on('startUpload', function() {
							me.progress = true;
						}).on('uploadFinished', function() {
							me.progress = false;
						});
						this.pool = [];
						this.stack = [];
						this.pending = [];
						this.remaning = 0;
						this.__tick = Base.bindFn(this._tick, this);
						owner.on('uploadComplete', function(file) {
							file.blocks && $.each(file.blocks, function(_, v) {
								v.transport && (v.transport.abort(), v.transport.destroy());
								delete v.transport;
							});
							delete file.blocks;
							delete file.remaning;
						});
					},
					reset: function() {
						this.request('stop-upload', true);
						this.runing = false;
						this.pool = [];
						this.stack = [];
						this.pending = [];
						this.remaning = 0;
						this._trigged = false;
						this._promise = null;
					},
					startUpload: function(file) {
						var me = this;
						$.each(me.request('get-files', Status.INVALID), function() {
							me.request('remove-file', this);
						});
						if(file) {
							file = file.id ? file : me.request('get-file', file);
							if(file.getStatus() === Status.INTERRUPT) {
								$.each(me.pool, function(_, v) {
									if(v.file !== file) {
										return;
									}
									v.transport && v.transport.send();
								});
								file.setStatus(Status.QUEUED);
							} else if(file.getStatus() === Status.PROGRESS) {
								return;
							} else {
								file.setStatus(Status.QUEUED);
							}
						} else {
							$.each(me.request('get-files', [Status.INITED]), function() {
								this.setStatus(Status.QUEUED);
							});
						}
						if(me.runing) {
							return;
						}
						me.runing = true;
						var files = [];
						$.each(me.pool, function(_, v) {
							var file = v.file;
							if(file.getStatus() === Status.INTERRUPT) {
								files.push(file);
								me._trigged = false;
								v.transport && v.transport.send();
							}
						});
						var file;
						while((file = files.shift())) {
							file.setStatus(Status.PROGRESS);
						}
						file || $.each(me.request('get-files', Status.INTERRUPT), function() {
							this.setStatus(Status.PROGRESS);
						});
						me._trigged = false;
						Base.nextTick(me.__tick);
						me.owner.trigger('startUpload');
					},
					stopUpload: function(file, interrupt) {
						var me = this;
						if(file === true) {
							interrupt = file;
							file = null;
						}
						if(me.runing === false) {
							return;
						}
						if(file) {
							file = file.id ? file : me.request('get-file', file);
							if(file.getStatus() !== Status.PROGRESS && file.getStatus() !== Status.QUEUED) {
								return;
							}
							file.setStatus(Status.INTERRUPT);
							$.each(me.pool, function(_, v) {
								if(v.file !== file) {
									return;
								}
								v.transport && v.transport.abort();
								me._putback(v);
								me._popBlock(v);
							});
							return Base.nextTick(me.__tick);
						}
						me.runing = false;
						if(this._promise && this._promise.file) {
							this._promise.file.setStatus(Status.INTERRUPT);
						}
						interrupt && $.each(me.pool, function(_, v) {
							v.transport && v.transport.abort();
							v.file.setStatus(Status.INTERRUPT);
						});
						me.owner.trigger('stopUpload');
					},
					cancelFile: function(file) {
						file = file.id ? file : this.request('get-file', file);
						file.blocks && $.each(file.blocks, function(_, v) {
							var _tr = v.transport;
							if(_tr) {
								_tr.abort();
								_tr.destroy();
								delete v.transport;
							}
						});
						file.setStatus(Status.CANCELLED);
						this.owner.trigger('fileDequeued', file);
					},
					isInProgress: function() {
						return !!this.progress;
					},
					_getStats: function() {
						return this.request('get-stats');
					},
					skipFile: function(file, status) {
						file = file.id ? file : this.request('get-file', file);
						file.setStatus(status || Status.COMPLETE);
						file.skipped = true;
						file.blocks && $.each(file.blocks, function(_, v) {
							var _tr = v.transport;
							if(_tr) {
								_tr.abort();
								_tr.destroy();
								delete v.transport;
							}
						});
						this.owner.trigger('uploadSkip', file);
					},
					_tick: function() {
						var me = this,
							opts = me.options,
							fn, val;
						if(me._promise) {
							return me._promise.always(me.__tick);
						}
						if(me.pool.length < opts.threads && (val = me._nextBlock())) {
							me._trigged = false;
							fn = function(val) {
								me._promise = null;
								val && val.file && me._startSend(val);
								Base.nextTick(me.__tick);
							};
							me._promise = isPromise(val) ? val.always(fn) : fn(val);
						} else if(!me.remaning && !me._getStats().numOfQueue && !me._getStats().numofInterrupt) {
							me.runing = false;
							me._trigged || Base.nextTick(function() {
								me.owner.trigger('uploadFinished');
							});
							me._trigged = true;
						}
					},
					_putback: function(block) {
						var idx;
						block.cuted.unshift(block);
						idx = this.stack.indexOf(block.cuted);
						if(!~idx) {
							this.stack.unshift(block.cuted);
						}
					},
					_getStack: function() {
						var i = 0,
							act;
						while((act = this.stack[i++])) {
							if(act.has() && act.file.getStatus() === Status.PROGRESS) {
								return act;
							} else if(!act.has() || act.file.getStatus() !== Status.PROGRESS && act.file.getStatus() !== Status.INTERRUPT) {
								this.stack.splice(--i, 1);
							}
						}
						return null;
					},
					_nextBlock: function() {
						var me = this,
							opts = me.options,
							act, next, done, preparing;
						if((act = this._getStack())) {
							if(opts.prepareNextFile && !me.pending.length) {
								me._prepareNextFile();
							}
							return act.shift();
						} else if(me.runing) {
							if(!me.pending.length && me._getStats().numOfQueue) {
								me._prepareNextFile();
							}
							next = me.pending.shift();
							done = function(file) {
								if(!file) {
									return null;
								}
								act = CuteFile(file, opts.chunked ? opts.chunkSize : 0);
								me.stack.push(act);
								return act.shift();
							};
							if(isPromise(next)) {
								preparing = next.file;
								next = next[next.pipe ? 'pipe' : 'then'](done);
								next.file = preparing;
								return next;
							}
							return done(next);
						}
					},
					_prepareNextFile: function() {
						var me = this,
							file = me.request('fetch-file'),
							pending = me.pending,
							promise;
						if(file) {
							promise = me.request('before-send-file', file, function() {
								if(file.getStatus() === Status.PROGRESS || file.getStatus() === Status.INTERRUPT) {
									return file;
								}
								return me._finishFile(file);
							});
							me.owner.trigger('uploadStart', file);
							file.setStatus(Status.PROGRESS);
							promise.file = file;
							promise.done(function() {
								var idx = $.inArray(promise, pending);
								~idx && pending.splice(idx, 1, file);
							});
							promise.fail(function(reason) {
								file.setStatus(Status.ERROR, reason);
								me.owner.trigger('uploadError', file, reason);
								me.owner.trigger('uploadComplete', file);
							});
							pending.push(promise);
						}
					},
					_popBlock: function(block) {
						var idx = $.inArray(block, this.pool);
						this.pool.splice(idx, 1);
						block.file.remaning--;
						this.remaning--;
					},
					_startSend: function(block) {
						var me = this,
							file = block.file,
							promise;
						if(file.getStatus() !== Status.PROGRESS) {
							if(file.getStatus() === Status.INTERRUPT) {
								me._putback(block);
							}
							return;
						}
						me.pool.push(block);
						me.remaning++;
						block.blob = block.chunks === 1 ? file.source : file.source.slice(block.start, block.end);
						promise = me.request('before-send', block, function() {
							if(file.getStatus() === Status.PROGRESS) {
								me._doSend(block);
							} else {
								me._popBlock(block);
								Base.nextTick(me.__tick);
							}
						});
						promise.fail(function() {
							if(file.remaning === 1) {
								me._finishFile(file).always(function() {
									block.percentage = 1;
									me._popBlock(block);
									me.owner.trigger('uploadComplete', file);
									Base.nextTick(me.__tick);
								});
							} else {
								block.percentage = 1;
								me.updateFileProgress(file);
								me._popBlock(block);
								Base.nextTick(me.__tick);
							}
						});
					},
					_doSend: function(block) {
						var me = this,
							owner = me.owner,
							opts = me.options,
							file = block.file,
							tr = new Transport(opts),
							data = $.extend({}, opts.formData),
							headers = $.extend({}, opts.headers),
							requestAccept, ret;
						block.transport = tr;
						tr.on('destroy', function() {
							delete block.transport;
							me._popBlock(block);
							Base.nextTick(me.__tick);
						});
						tr.on('progress', function(percentage) {
							block.percentage = percentage;
							me.updateFileProgress(file);
						});
						requestAccept = function(reject) {
							var fn;
							ret = tr.getResponseAsJson() || {};
							ret._raw = tr.getResponse();
							fn = function(value) {
								reject = value;
							};
							if(!owner.trigger('uploadAccept', block, ret, fn)) {
								reject = reject || 'server';
							}
							return reject;
						};
						tr.on('error', function(type, flag) {
							block.retried = block.retried || 0;
							if(block.chunks > 1 && ~'http,abort'.indexOf(type) && block.retried < opts.chunkRetry) {
								block.retried++;
								tr.send();
							} else {
								if(!flag && type === 'server') {
									type = requestAccept(type);
								}
								file.setStatus(Status.ERROR, type);
								owner.trigger('uploadError', file, type);
								owner.trigger('uploadComplete', file);
							}
						});
						tr.on('load', function() {
							var reason;
							if((reason = requestAccept())) {
								tr.trigger('error', reason, true);
								return;
							}
							if(file.remaning === 1) {
								me._finishFile(file, ret);
							} else {
								tr.destroy();
							}
						});
						data = $.extend(data, {
							id: file.id,
							name: file.name,
							type: file.type,
							lastModifiedDate: file.lastModifiedDate,
							size: file.size
						});
						block.chunks > 1 && $.extend(data, {
							chunks: block.chunks,
							chunk: block.chunk
						});
						owner.trigger('uploadBeforeSend', block, data, headers);
						tr.appendBlob(opts.fileVal, block.blob, file.name);
						tr.append(data);
						tr.setRequestHeader(headers);
						tr.send();
					},
					_finishFile: function(file, ret, hds) {
						var owner = this.owner;
						return owner.request('after-send-file', arguments, function() {
							file.setStatus(Status.COMPLETE);
							owner.trigger('uploadSuccess', file, ret, hds);
						}).fail(function(reason) {
							if(file.getStatus() === Status.PROGRESS) {
								file.setStatus(Status.ERROR, reason);
							}
							owner.trigger('uploadError', file, reason);
						}).always(function() {
							owner.trigger('uploadComplete', file);
						});
					},
					updateFileProgress: function(file) {
						var totalPercent = 0,
							uploaded = 0;
						if(!file.blocks) {
							return;
						}
						$.each(file.blocks, function(_, v) {
							uploaded += (v.percentage || 0) * (v.end - v.start);
						});
						totalPercent = uploaded / file.size;
						this.owner.trigger('uploadProgress', file, totalPercent || 0);
					}
				});
			});
			define('widgets/validator', ['base', 'uploader', 'file', 'widgets/widget'], function(Base, Uploader, WUFile) {
				var $ = Base.$,
					validators = {},
					api;
				api = {
					addValidator: function(type, cb) {
						validators[type] = cb;
					},
					removeValidator: function(type) {
						delete validators[type];
					}
				};
				Uploader.register({
					name: 'validator',
					init: function() {
						var me = this;
						Base.nextTick(function() {
							$.each(validators, function() {
								this.call(me.owner);
							});
						});
					}
				});
				api.addValidator('fileNumLimit', function() {
					var uploader = this,
						opts = uploader.options,
						count = 0,
						max = parseInt(opts.fileNumLimit, 10),
						flag = true;
					if(!max) {
						return;
					}
					uploader.on('beforeFileQueued', function(file) {
						if(count >= max && flag) {
							flag = false;
							this.trigger('error', 'Q_EXCEED_NUM_LIMIT', max, file);
							setTimeout(function() {
								flag = true;
							}, 1);
						}
						return count >= max ? false : true;
					});
					uploader.on('fileQueued', function() {
						count++;
					});
					uploader.on('fileDequeued', function() {
						count--;
					});
					uploader.on('reset', function() {
						count = 0;
					});
				});
				api.addValidator('fileSizeLimit', function() {
					var uploader = this,
						opts = uploader.options,
						count = 0,
						max = parseInt(opts.fileSizeLimit, 10),
						flag = true;
					if(!max) {
						return;
					}
					uploader.on('beforeFileQueued', function(file) {
						var invalid = count + file.size > max;
						if(invalid && flag) {
							flag = false;
							this.trigger('error', 'Q_EXCEED_SIZE_LIMIT', max, file);
							setTimeout(function() {
								flag = true;
							}, 1);
						}
						return invalid ? false : true;
					});
					uploader.on('fileQueued', function(file) {
						count += file.size;
					});
					uploader.on('fileDequeued', function(file) {
						count -= file.size;
					});
					uploader.on('reset', function() {
						count = 0;
					});
				});
				api.addValidator('fileSingleSizeLimit', function() {
					var uploader = this,
						opts = uploader.options,
						max = opts.fileSingleSizeLimit;
					if(!max) {
						return;
					}
					uploader.on('beforeFileQueued', function(file) {
						if(file.size > max) {
							file.setStatus(WUFile.Status.INVALID, 'exceed_size');
							this.trigger('error', 'F_EXCEED_SIZE', max, file);
							return false;
						}
					});
				});
				api.addValidator('duplicate', function() {
					var uploader = this,
						opts = uploader.options,
						mapping = {};
					if(opts.duplicate) {
						return;
					}

					function hashString(str) {
						var hash = 0,
							i = 0,
							len = str.length,
							_char;
						for(; i < len; i++) {
							_char = str.charCodeAt(i);
							hash = _char + (hash << 6) + (hash << 16) - hash;
						}
						return hash;
					}
					uploader.on('beforeFileQueued', function(file) {
						var hash = file.__hash || (file.__hash = hashString(file.name +
							file.size + file.lastModifiedDate));
						if(mapping[hash]) {
							this.trigger('error', 'F_DUPLICATE', file);
							return false;
						}
					});
					uploader.on('fileQueued', function(file) {
						var hash = file.__hash;
						hash && (mapping[hash] = true);
					});
					uploader.on('fileDequeued', function(file) {
						var hash = file.__hash;
						hash && (delete mapping[hash]);
					});
					uploader.on('reset', function() {
						mapping = {};
					});
				});
				return api;
			});
			define('lib/md5', ['runtime/client', 'mediator'], function(RuntimeClient, Mediator) {
				function Md5() {
					RuntimeClient.call(this, 'Md5');
				}
				Mediator.installTo(Md5.prototype);
				Md5.prototype.loadFromBlob = function(blob) {
					var me = this;
					if(me.getRuid()) {
						me.disconnectRuntime();
					}
					me.connectRuntime(blob.ruid, function() {
						me.exec('init');
						me.exec('loadFromBlob', blob);
					});
				};
				Md5.prototype.getResult = function() {
					return this.exec('getResult');
				};
				return Md5;
			});
			define('widgets/md5', ['base', 'uploader', 'lib/md5', 'lib/blob', 'widgets/widget'], function(Base, Uploader, Md5, Blob) {
				return Uploader.register({
					name: 'md5',
					md5File: function(file, start, end) {
						var md5 = new Md5(),
							deferred = Base.Deferred(),
							blob = (file instanceof Blob) ? file : this.request('get-file', file).source;
						md5.on('progress load', function(e) {
							e = e || {};
							deferred.notify(e.total ? e.loaded / e.total : 1);
						});
						md5.on('complete', function() {
							deferred.resolve(md5.getResult());
						});
						md5.on('error', function(reason) {
							deferred.reject(reason);
						});
						if(arguments.length > 1) {
							start = start || 0;
							end = end || 0;
							start < 0 && (start = blob.size + start);
							end < 0 && (end = blob.size + end);
							end = Math.min(end, blob.size);
							blob = blob.slice(start, end);
						}
						md5.loadFromBlob(blob);
						return deferred.promise();
					}
				});
			});
			define('runtime/compbase', [], function() {
				function CompBase(owner, runtime) {
					this.owner = owner;
					this.options = owner.options;
					this.getRuntime = function() {
						return runtime;
					};
					this.getRuid = function() {
						return runtime.uid;
					};
					this.trigger = function() {
						return owner.trigger.apply(owner, arguments);
					};
				}
				return CompBase;
			});
			define('runtime/html5/runtime', ['base', 'runtime/runtime', 'runtime/compbase'], function(Base, Runtime, CompBase) {
				var type = 'html5',
					components = {};

				function Html5Runtime() {
					var pool = {},
						me = this,
						destroy = this.destroy;
					Runtime.apply(me, arguments);
					me.type = type;
					me.exec = function(comp, fn) {
						var client = this,
							uid = client.uid,
							args = Base.slice(arguments, 2),
							instance;
						if(components[comp]) {
							instance = pool[uid] = pool[uid] || new components[comp](client, me);
							if(instance[fn]) {
								return instance[fn].apply(instance, args);
							}
						}
					};
					me.destroy = function() {
						return destroy && destroy.apply(this, arguments);
					};
				}
				Base.inherits(Runtime, {
					constructor: Html5Runtime,
					init: function() {
						var me = this;
						setTimeout(function() {
							me.trigger('ready');
						}, 1);
					}
				});
				Html5Runtime.register = function(name, component) {
					var klass = components[name] = Base.inherits(CompBase, component);
					return klass;
				};
				if(window.Blob && window.FileReader && window.DataView) {
					Runtime.addRuntime(type, Html5Runtime);
				}
				return Html5Runtime;
			});
			define('runtime/html5/blob', ['runtime/html5/runtime', 'lib/blob'], function(Html5Runtime, Blob) {
				return Html5Runtime.register('Blob', {
					slice: function(start, end) {
						var blob = this.owner.source,
							slice = blob.slice || blob.webkitSlice || blob.mozSlice;
						blob = slice.call(blob, start, end);
						return new Blob(this.getRuid(), blob);
					}
				});
			});
			define('runtime/html5/dnd', ['base', 'runtime/html5/runtime', 'lib/file'], function(Base, Html5Runtime, File) {
				var $ = Base.$,
					prefix = 'webuploader-dnd-';
				return Html5Runtime.register('DragAndDrop', {
					init: function() {
						var elem = this.elem = this.options.container;
						this.dragEnterHandler = Base.bindFn(this._dragEnterHandler, this);
						this.dragOverHandler = Base.bindFn(this._dragOverHandler, this);
						this.dragLeaveHandler = Base.bindFn(this._dragLeaveHandler, this);
						this.dropHandler = Base.bindFn(this._dropHandler, this);
						this.dndOver = false;
						elem.on('dragenter', this.dragEnterHandler);
						elem.on('dragover', this.dragOverHandler);
						elem.on('dragleave', this.dragLeaveHandler);
						elem.on('drop', this.dropHandler);
						if(this.options.disableGlobalDnd) {
							$(document).on('dragover', this.dragOverHandler);
							$(document).on('drop', this.dropHandler);
						}
					},
					_dragEnterHandler: function(e) {
						var me = this,
							denied = me._denied || false,
							items;
						e = e.originalEvent || e;
						if(!me.dndOver) {
							me.dndOver = true;
							items = e.dataTransfer.items;
							if(items && items.length) {
								me._denied = denied = !me.trigger('accept', items);
							}
							me.elem.addClass(prefix + 'over');
							me.elem[denied ? 'addClass' : 'removeClass'](prefix + 'denied');
						}
						e.dataTransfer.dropEffect = denied ? 'none' : 'copy';
						return false;
					},
					_dragOverHandler: function(e) {
						var parentElem = this.elem.parent().get(0);
						if(parentElem && !$.contains(parentElem, e.currentTarget)) {
							return false;
						}
						clearTimeout(this._leaveTimer);
						this._dragEnterHandler.call(this, e);
						return false;
					},
					_dragLeaveHandler: function() {
						var me = this,
							handler;
						handler = function() {
							me.dndOver = false;
							me.elem.removeClass(prefix + 'over ' + prefix + 'denied');
						};
						clearTimeout(me._leaveTimer);
						me._leaveTimer = setTimeout(handler, 100);
						return false;
					},
					_dropHandler: function(e) {
						var me = this,
							ruid = me.getRuid(),
							parentElem = me.elem.parent().get(0),
							dataTransfer, data;
						if(parentElem && !$.contains(parentElem, e.currentTarget)) {
							return false;
						}
						e = e.originalEvent || e;
						dataTransfer = e.dataTransfer;
						try {
							data = dataTransfer.getData('text/html');
						} catch(err) {}
						if(data) {
							return;
						}
						me._getTansferFiles(dataTransfer, function(results) {
							me.trigger('drop', $.map(results, function(file) {
								return new File(ruid, file);
							}));
						});
						me.dndOver = false;
						me.elem.removeClass(prefix + 'over');
						return false;
					},
					_getTansferFiles: function(dataTransfer, callback) {
						var results = [],
							promises = [],
							items, files, file, item, i, len, canAccessFolder;
						items = dataTransfer.items;
						files = dataTransfer.files;
						canAccessFolder = !!(items && items[0].webkitGetAsEntry);
						for(i = 0, len = files.length; i < len; i++) {
							file = files[i];
							item = items && items[i];
							if(canAccessFolder && item.webkitGetAsEntry().isDirectory) {
								promises.push(this._traverseDirectoryTree(item.webkitGetAsEntry(), results));
							} else {
								results.push(file);
							}
						}
						Base.when.apply(Base, promises).done(function() {
							if(!results.length) {
								return;
							}
							callback(results);
						});
					},
					_traverseDirectoryTree: function(entry, results) {
						var deferred = Base.Deferred(),
							me = this;
						if(entry.isFile) {
							entry.file(function(file) {
								results.push(file);
								deferred.resolve();
							});
						} else if(entry.isDirectory) {
							entry.createReader().readEntries(function(entries) {
								var len = entries.length,
									promises = [],
									arr = [],
									i;
								for(i = 0; i < len; i++) {
									promises.push(me._traverseDirectoryTree(entries[i], arr));
								}
								Base.when.apply(Base, promises).then(function() {
									results.push.apply(results, arr);
									deferred.resolve();
								}, deferred.reject);
							});
						}
						return deferred.promise();
					},
					destroy: function() {
						var elem = this.elem;
						if(!elem) {
							return;
						}
						elem.off('dragenter', this.dragEnterHandler);
						elem.off('dragover', this.dragOverHandler);
						elem.off('dragleave', this.dragLeaveHandler);
						elem.off('drop', this.dropHandler);
						if(this.options.disableGlobalDnd) {
							$(document).off('dragover', this.dragOverHandler);
							$(document).off('drop', this.dropHandler);
						}
					}
				});
			});
			define('runtime/html5/filepaste', ['base', 'runtime/html5/runtime', 'lib/file'], function(Base, Html5Runtime, File) {
				return Html5Runtime.register('FilePaste', {
					init: function() {
						var opts = this.options,
							elem = this.elem = opts.container,
							accept = '.*',
							arr, i, len, item;
						if(opts.accept) {
							arr = [];
							for(i = 0, len = opts.accept.length; i < len; i++) {
								item = opts.accept[i].mimeTypes;
								item && arr.push(item);
							}
							if(arr.length) {
								accept = arr.join(',');
								accept = accept.replace(/,/g, '|').replace(/\*/g, '.*');
							}
						}
						this.accept = accept = new RegExp(accept, 'i');
						this.hander = Base.bindFn(this._pasteHander, this);
						elem.on('paste', this.hander);
					},
					_pasteHander: function(e) {
						var allowed = [],
							ruid = this.getRuid(),
							items, item, blob, i, len;
						e = e.originalEvent || e;
						items = e.clipboardData.items;
						for(i = 0, len = items.length; i < len; i++) {
							item = items[i];
							if(item.kind !== 'file' || !(blob = item.getAsFile())) {
								continue;
							}
							allowed.push(new File(ruid, blob));
						}
						if(allowed.length) {
							e.preventDefault();
							e.stopPropagation();
							this.trigger('paste', allowed);
						}
					},
					destroy: function() {
						this.elem.off('paste', this.hander);
					}
				});
			});
			define('runtime/html5/filepicker', ['base', 'runtime/html5/runtime'], function(Base, Html5Runtime) {
				var $ = Base.$;
				return Html5Runtime.register('FilePicker', {
					init: function() {
						var container = this.getRuntime().getContainer(),
							me = this,
							owner = me.owner,
							opts = me.options,
							label = this.label = $(document.createElement('label')),
							input = this.input = $(document.createElement('input')),
							arr, i, len, mouseHandler;
						input.attr('type', 'file');
						input.attr('name', opts.name);
						input.addClass('webuploader-element-invisible');
						label.on('click', function() {
							input.trigger('click');
						});
						if (opts.webkitdirectory) {
						    input.attr('webkitdirectory', true);
						}
						label.css({
							opacity: 0,
							width: '100%',
							height: '100%',
							display: 'block',
							cursor: 'pointer',
							background: '#ffffff'
						});
						if(opts.multiple) {
							input.attr('multiple', 'multiple');
						}
						if(opts.accept && opts.accept.length > 0) {
							arr = [];
							for(i = 0, len = opts.accept.length; i < len; i++) {
								arr.push(opts.accept[i].mimeTypes);
							}
							input.attr('accept', arr.join(','));
						}
						container.append(input);
						container.append(label);
						mouseHandler = function(e) {
							owner.trigger(e.type);
						};
						input.on('change', function(e) {
							var fn = arguments.callee,
								clone;
							me.files = e.target.files;
							clone = this.cloneNode(true);
							clone.value = null;
							this.parentNode.replaceChild(clone, this);
							input.off();
							input = $(clone).on('change', fn).on('mouseenter mouseleave', mouseHandler);
							owner.trigger('change');
						});
						label.on('mouseenter mouseleave', mouseHandler);
					},
					getFiles: function() {
						return this.files;
					},
					destroy: function() {
						this.input.off();
						this.label.off();
					}
				});
			});
			define('runtime/html5/util', ['base'], function(Base) {
				var urlAPI = window.createObjectURL && window || window.URL && URL.revokeObjectURL && URL || window.webkitURL,
					createObjectURL = Base.noop,
					revokeObjectURL = createObjectURL;
				if(urlAPI) {
					createObjectURL = function() {
						return urlAPI.createObjectURL.apply(urlAPI, arguments);
					};
					revokeObjectURL = function() {
						return urlAPI.revokeObjectURL.apply(urlAPI, arguments);
					};
				}
				return {
					createObjectURL: createObjectURL,
					revokeObjectURL: revokeObjectURL,
					dataURL2Blob: function(dataURI) {
						var byteStr, intArray, ab, i, mimetype, parts;
						parts = dataURI.split(',');
						if(~parts[0].indexOf('base64')) {
							byteStr = atob(parts[1]);
						} else {
							byteStr = decodeURIComponent(parts[1]);
						}
						ab = new ArrayBuffer(byteStr.length);
						intArray = new Uint8Array(ab);
						for(i = 0; i < byteStr.length; i++) {
							intArray[i] = byteStr.charCodeAt(i);
						}
						mimetype = parts[0].split(':')[1].split(';')[0];
						return this.arrayBufferToBlob(ab, mimetype);
					},
					dataURL2ArrayBuffer: function(dataURI) {
						var byteStr, intArray, i, parts;
						parts = dataURI.split(',');
						if(~parts[0].indexOf('base64')) {
							byteStr = atob(parts[1]);
						} else {
							byteStr = decodeURIComponent(parts[1]);
						}
						intArray = new Uint8Array(byteStr.length);
						for(i = 0; i < byteStr.length; i++) {
							intArray[i] = byteStr.charCodeAt(i);
						}
						return intArray.buffer;
					},
					arrayBufferToBlob: function(buffer, type) {
						var builder = window.BlobBuilder || window.WebKitBlobBuilder,
							bb;
						if(builder) {
							bb = new builder();
							bb.append(buffer);
							return bb.getBlob(type);
						}
						return new Blob([buffer], type ? {
							type: type
						} : {});
					},
					canvasToDataUrl: function(canvas, type, quality) {
						return canvas.toDataURL(type, quality / 100);
					},
					parseMeta: function(blob, callback) {
						callback(false, {});
					},
					updateImageHead: function(data) {
						return data;
					}
				};
			});
			define('runtime/html5/imagemeta', ['runtime/html5/util'], function(Util) {
				var api;
				api = {
					parsers: {
						0xffe1: []
					},
					maxMetaDataSize: 262144,
					parse: function(blob, cb) {
						var me = this,
							fr = new FileReader();
						fr.onload = function() {
							cb(false, me._parse(this.result));
							fr = fr.onload = fr.onerror = null;
						};
						fr.onerror = function(e) {
							cb(e.message);
							fr = fr.onload = fr.onerror = null;
						};
						blob = blob.slice(0, me.maxMetaDataSize);
						fr.readAsArrayBuffer(blob.getSource());
					},
					_parse: function(buffer, noParse) {
						if(buffer.byteLength < 6) {
							return;
						}
						var dataview = new DataView(buffer),
							offset = 2,
							maxOffset = dataview.byteLength - 4,
							headLength = offset,
							ret = {},
							markerBytes, markerLength, parsers, i;
						if(dataview.getUint16(0) === 0xffd8) {
							while(offset < maxOffset) {
								markerBytes = dataview.getUint16(offset);
								if(markerBytes >= 0xffe0 && markerBytes <= 0xffef || markerBytes === 0xfffe) {
									markerLength = dataview.getUint16(offset + 2) + 2;
									if(offset + markerLength > dataview.byteLength) {
										break;
									}
									parsers = api.parsers[markerBytes];
									if(!noParse && parsers) {
										for(i = 0; i < parsers.length; i += 1) {
											parsers[i].call(api, dataview, offset, markerLength, ret);
										}
									}
									offset += markerLength;
									headLength = offset;
								} else {
									break;
								}
							}
							if(headLength > 6) {
								if(buffer.slice) {
									ret.imageHead = buffer.slice(2, headLength);
								} else {
									ret.imageHead = new Uint8Array(buffer).subarray(2, headLength);
								}
							}
						}
						return ret;
					},
					updateImageHead: function(buffer, head) {
						var data = this._parse(buffer, true),
							buf1, buf2, bodyoffset;
						bodyoffset = 2;
						if(data.imageHead) {
							bodyoffset = 2 + data.imageHead.byteLength;
						}
						if(buffer.slice) {
							buf2 = buffer.slice(bodyoffset);
						} else {
							buf2 = new Uint8Array(buffer).subarray(bodyoffset);
						}
						buf1 = new Uint8Array(head.byteLength + 2 + buf2.byteLength);
						buf1[0] = 0xFF;
						buf1[1] = 0xD8;
						buf1.set(new Uint8Array(head), 2);
						buf1.set(new Uint8Array(buf2), head.byteLength + 2);
						return buf1.buffer;
					}
				};
				Util.parseMeta = function() {
					return api.parse.apply(api, arguments);
				};
				Util.updateImageHead = function() {
					return api.updateImageHead.apply(api, arguments);
				};
				return api;
			});
			define('runtime/html5/imagemeta/exif', ['base', 'runtime/html5/imagemeta'], function(Base, ImageMeta) {
				var EXIF = {};
				EXIF.ExifMap = function() {
					return this;
				};
				EXIF.ExifMap.prototype.map = {
					'Orientation': 0x0112
				};
				EXIF.ExifMap.prototype.get = function(id) {
					return this[id] || this[this.map[id]];
				};
				EXIF.exifTagTypes = {
					1: {
						getValue: function(dataView, dataOffset) {
							return dataView.getUint8(dataOffset);
						},
						size: 1
					},
					2: {
						getValue: function(dataView, dataOffset) {
							return String.fromCharCode(dataView.getUint8(dataOffset));
						},
						size: 1,
						ascii: true
					},
					3: {
						getValue: function(dataView, dataOffset, littleEndian) {
							return dataView.getUint16(dataOffset, littleEndian);
						},
						size: 2
					},
					4: {
						getValue: function(dataView, dataOffset, littleEndian) {
							return dataView.getUint32(dataOffset, littleEndian);
						},
						size: 4
					},
					5: {
						getValue: function(dataView, dataOffset, littleEndian) {
							return dataView.getUint32(dataOffset, littleEndian) / dataView.getUint32(dataOffset + 4, littleEndian);
						},
						size: 8
					},
					9: {
						getValue: function(dataView, dataOffset, littleEndian) {
							return dataView.getInt32(dataOffset, littleEndian);
						},
						size: 4
					},
					10: {
						getValue: function(dataView, dataOffset, littleEndian) {
							return dataView.getInt32(dataOffset, littleEndian) / dataView.getInt32(dataOffset + 4, littleEndian);
						},
						size: 8
					}
				};
				EXIF.exifTagTypes[7] = EXIF.exifTagTypes[1];
				EXIF.getExifValue = function(dataView, tiffOffset, offset, type, length, littleEndian) {
					var tagType = EXIF.exifTagTypes[type],
						tagSize, dataOffset, values, i, str, c;
					if(!tagType) {
						Base.log('Invalid Exif data: Invalid tag type.');
						return;
					}
					tagSize = tagType.size * length;
					dataOffset = tagSize > 4 ? tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
					if(dataOffset + tagSize > dataView.byteLength) {
						Base.log('Invalid Exif data: Invalid data offset.');
						return;
					}
					if(length === 1) {
						return tagType.getValue(dataView, dataOffset, littleEndian);
					}
					values = [];
					for(i = 0; i < length; i += 1) {
						values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
					}
					if(tagType.ascii) {
						str = '';
						for(i = 0; i < values.length; i += 1) {
							c = values[i];
							if(c === '\u0000') {
								break;
							}
							str += c;
						}
						return str;
					}
					return values;
				};
				EXIF.parseExifTag = function(dataView, tiffOffset, offset, littleEndian, data) {
					var tag = dataView.getUint16(offset, littleEndian);
					data.exif[tag] = EXIF.getExifValue(dataView, tiffOffset, offset, dataView.getUint16(offset + 2, littleEndian), dataView.getUint32(offset + 4, littleEndian), littleEndian);
				};
				EXIF.parseExifTags = function(dataView, tiffOffset, dirOffset, littleEndian, data) {
					var tagsNumber, dirEndOffset, i;
					if(dirOffset + 6 > dataView.byteLength) {
						Base.log('Invalid Exif data: Invalid directory offset.');
						return;
					}
					tagsNumber = dataView.getUint16(dirOffset, littleEndian);
					dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
					if(dirEndOffset + 4 > dataView.byteLength) {
						Base.log('Invalid Exif data: Invalid directory size.');
						return;
					}
					for(i = 0; i < tagsNumber; i += 1) {
						this.parseExifTag(dataView, tiffOffset, dirOffset + 2 + 12 * i, littleEndian, data);
					}
					return dataView.getUint32(dirEndOffset, littleEndian);
				};
				EXIF.parseExifData = function(dataView, offset, length, data) {
					var tiffOffset = offset + 10,
						littleEndian, dirOffset;
					if(dataView.getUint32(offset + 4) !== 0x45786966) {
						return;
					}
					if(tiffOffset + 8 > dataView.byteLength) {
						Base.log('Invalid Exif data: Invalid segment size.');
						return;
					}
					if(dataView.getUint16(offset + 8) !== 0x0000) {
						Base.log('Invalid Exif data: Missing byte alignment offset.');
						return;
					}
					switch(dataView.getUint16(tiffOffset)) {
						case 0x4949:
							littleEndian = true;
							break;
						case 0x4D4D:
							littleEndian = false;
							break;
						default:
							Base.log('Invalid Exif data: Invalid byte alignment marker.');
							return;
					}
					if(dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
						Base.log('Invalid Exif data: Missing TIFF marker.');
						return;
					}
					dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
					data.exif = new EXIF.ExifMap();
					dirOffset = EXIF.parseExifTags(dataView, tiffOffset, tiffOffset + dirOffset, littleEndian, data);
				};
				ImageMeta.parsers[0xffe1].push(EXIF.parseExifData);
				return EXIF;
			});
			define('runtime/html5/jpegencoder', [], function(require, exports, module) {
				function JPEGEncoder(quality) {
					var self = this;
					var fround = Math.round;
					var ffloor = Math.floor;
					var YTable = new Array(64);
					var UVTable = new Array(64);
					var fdtbl_Y = new Array(64);
					var fdtbl_UV = new Array(64);
					var YDC_HT;
					var UVDC_HT;
					var YAC_HT;
					var UVAC_HT;
					var bitcode = new Array(65535);
					var category = new Array(65535);
					var outputfDCTQuant = new Array(64);
					var DU = new Array(64);
					var byteout = [];
					var bytenew = 0;
					var bytepos = 7;
					var YDU = new Array(64);
					var UDU = new Array(64);
					var VDU = new Array(64);
					var clt = new Array(256);
					var RGB_YUV_TABLE = new Array(2048);
					var currentQuality;
					var ZigZag = [0, 1, 5, 6, 14, 15, 27, 28, 2, 4, 7, 13, 16, 26, 29, 42, 3, 8, 12, 17, 25, 30, 41, 43, 9, 11, 18, 24, 31, 40, 44, 53, 10, 19, 23, 32, 39, 45, 52, 54, 20, 22, 33, 38, 46, 51, 55, 60, 21, 34, 37, 47, 50, 56, 59, 61, 35, 36, 48, 49, 57, 58, 62, 63];
					var std_dc_luminance_nrcodes = [0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0];
					var std_dc_luminance_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
					var std_ac_luminance_nrcodes = [0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7d];
					var std_ac_luminance_values = [0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa];
					var std_dc_chrominance_nrcodes = [0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0];
					var std_dc_chrominance_values = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
					var std_ac_chrominance_nrcodes = [0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77];
					var std_ac_chrominance_values = [0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa];

					function initQuantTables(sf) {
						var YQT = [16, 11, 10, 16, 24, 40, 51, 61, 12, 12, 14, 19, 26, 58, 60, 55, 14, 13, 16, 24, 40, 57, 69, 56, 14, 17, 22, 29, 51, 87, 80, 62, 18, 22, 37, 56, 68, 109, 103, 77, 24, 35, 55, 64, 81, 104, 113, 92, 49, 64, 78, 87, 103, 121, 120, 101, 72, 92, 95, 98, 112, 100, 103, 99];
						for(var i = 0; i < 64; i++) {
							var t = ffloor((YQT[i] * sf + 50) / 100);
							if(t < 1) {
								t = 1;
							} else if(t > 255) {
								t = 255;
							}
							YTable[ZigZag[i]] = t;
						}
						var UVQT = [17, 18, 24, 47, 99, 99, 99, 99, 18, 21, 26, 66, 99, 99, 99, 99, 24, 26, 56, 99, 99, 99, 99, 99, 47, 66, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99];
						for(var j = 0; j < 64; j++) {
							var u = ffloor((UVQT[j] * sf + 50) / 100);
							if(u < 1) {
								u = 1;
							} else if(u > 255) {
								u = 255;
							}
							UVTable[ZigZag[j]] = u;
						}
						var aasf = [1.0, 1.387039845, 1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379];
						var k = 0;
						for(var row = 0; row < 8; row++) {
							for(var col = 0; col < 8; col++) {
								fdtbl_Y[k] = (1.0 / (YTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));
								fdtbl_UV[k] = (1.0 / (UVTable[ZigZag[k]] * aasf[row] * aasf[col] * 8.0));
								k++;
							}
						}
					}

					function computeHuffmanTbl(nrcodes, std_table) {
						var codevalue = 0;
						var pos_in_table = 0;
						var HT = new Array();
						for(var k = 1; k <= 16; k++) {
							for(var j = 1; j <= nrcodes[k]; j++) {
								HT[std_table[pos_in_table]] = [];
								HT[std_table[pos_in_table]][0] = codevalue;
								HT[std_table[pos_in_table]][1] = k;
								pos_in_table++;
								codevalue++;
							}
							codevalue *= 2;
						}
						return HT;
					}

					function initHuffmanTbl() {
						YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes, std_dc_luminance_values);
						UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes, std_dc_chrominance_values);
						YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes, std_ac_luminance_values);
						UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes, std_ac_chrominance_values);
					}

					function initCategoryNumber() {
						var nrlower = 1;
						var nrupper = 2;
						for(var cat = 1; cat <= 15; cat++) {
							for(var nr = nrlower; nr < nrupper; nr++) {
								category[32767 + nr] = cat;
								bitcode[32767 + nr] = [];
								bitcode[32767 + nr][1] = cat;
								bitcode[32767 + nr][0] = nr;
							}
							for(var nrneg = -(nrupper - 1); nrneg <= -nrlower; nrneg++) {
								category[32767 + nrneg] = cat;
								bitcode[32767 + nrneg] = [];
								bitcode[32767 + nrneg][1] = cat;
								bitcode[32767 + nrneg][0] = nrupper - 1 + nrneg;
							}
							nrlower <<= 1;
							nrupper <<= 1;
						}
					}

					function initRGBYUVTable() {
						for(var i = 0; i < 256; i++) {
							RGB_YUV_TABLE[i] = 19595 * i;
							RGB_YUV_TABLE[(i + 256) >> 0] = 38470 * i;
							RGB_YUV_TABLE[(i + 512) >> 0] = 7471 * i + 0x8000;
							RGB_YUV_TABLE[(i + 768) >> 0] = -11059 * i;
							RGB_YUV_TABLE[(i + 1024) >> 0] = -21709 * i;
							RGB_YUV_TABLE[(i + 1280) >> 0] = 32768 * i + 0x807FFF;
							RGB_YUV_TABLE[(i + 1536) >> 0] = -27439 * i;
							RGB_YUV_TABLE[(i + 1792) >> 0] = -5329 * i;
						}
					}

					function writeBits(bs) {
						var value = bs[0];
						var posval = bs[1] - 1;
						while(posval >= 0) {
							if(value & (1 << posval)) {
								bytenew |= (1 << bytepos);
							}
							posval--;
							bytepos--;
							if(bytepos < 0) {
								if(bytenew == 0xFF) {
									writeByte(0xFF);
									writeByte(0);
								} else {
									writeByte(bytenew);
								}
								bytepos = 7;
								bytenew = 0;
							}
						}
					}

					function writeByte(value) {
						byteout.push(clt[value]);
					}

					function writeWord(value) {
						writeByte((value >> 8) & 0xFF);
						writeByte((value) & 0xFF);
					}

					function fDCTQuant(data, fdtbl) {
						var d0, d1, d2, d3, d4, d5, d6, d7;
						var dataOff = 0;
						var i;
						var I8 = 8;
						var I64 = 64;
						for(i = 0; i < I8; ++i) {
							d0 = data[dataOff];
							d1 = data[dataOff + 1];
							d2 = data[dataOff + 2];
							d3 = data[dataOff + 3];
							d4 = data[dataOff + 4];
							d5 = data[dataOff + 5];
							d6 = data[dataOff + 6];
							d7 = data[dataOff + 7];
							var tmp0 = d0 + d7;
							var tmp7 = d0 - d7;
							var tmp1 = d1 + d6;
							var tmp6 = d1 - d6;
							var tmp2 = d2 + d5;
							var tmp5 = d2 - d5;
							var tmp3 = d3 + d4;
							var tmp4 = d3 - d4;
							var tmp10 = tmp0 + tmp3;
							var tmp13 = tmp0 - tmp3;
							var tmp11 = tmp1 + tmp2;
							var tmp12 = tmp1 - tmp2;
							data[dataOff] = tmp10 + tmp11;
							data[dataOff + 4] = tmp10 - tmp11;
							var z1 = (tmp12 + tmp13) * 0.707106781;
							data[dataOff + 2] = tmp13 + z1;
							data[dataOff + 6] = tmp13 - z1;
							tmp10 = tmp4 + tmp5;
							tmp11 = tmp5 + tmp6;
							tmp12 = tmp6 + tmp7;
							var z5 = (tmp10 - tmp12) * 0.382683433;
							var z2 = 0.541196100 * tmp10 + z5;
							var z4 = 1.306562965 * tmp12 + z5;
							var z3 = tmp11 * 0.707106781;
							var z11 = tmp7 + z3;
							var z13 = tmp7 - z3;
							data[dataOff + 5] = z13 + z2;
							data[dataOff + 3] = z13 - z2;
							data[dataOff + 1] = z11 + z4;
							data[dataOff + 7] = z11 - z4;
							dataOff += 8;
						}
						dataOff = 0;
						for(i = 0; i < I8; ++i) {
							d0 = data[dataOff];
							d1 = data[dataOff + 8];
							d2 = data[dataOff + 16];
							d3 = data[dataOff + 24];
							d4 = data[dataOff + 32];
							d5 = data[dataOff + 40];
							d6 = data[dataOff + 48];
							d7 = data[dataOff + 56];
							var tmp0p2 = d0 + d7;
							var tmp7p2 = d0 - d7;
							var tmp1p2 = d1 + d6;
							var tmp6p2 = d1 - d6;
							var tmp2p2 = d2 + d5;
							var tmp5p2 = d2 - d5;
							var tmp3p2 = d3 + d4;
							var tmp4p2 = d3 - d4;
							var tmp10p2 = tmp0p2 + tmp3p2;
							var tmp13p2 = tmp0p2 - tmp3p2;
							var tmp11p2 = tmp1p2 + tmp2p2;
							var tmp12p2 = tmp1p2 - tmp2p2;
							data[dataOff] = tmp10p2 + tmp11p2;
							data[dataOff + 32] = tmp10p2 - tmp11p2;
							var z1p2 = (tmp12p2 + tmp13p2) * 0.707106781;
							data[dataOff + 16] = tmp13p2 + z1p2;
							data[dataOff + 48] = tmp13p2 - z1p2;
							tmp10p2 = tmp4p2 + tmp5p2;
							tmp11p2 = tmp5p2 + tmp6p2;
							tmp12p2 = tmp6p2 + tmp7p2;
							var z5p2 = (tmp10p2 - tmp12p2) * 0.382683433;
							var z2p2 = 0.541196100 * tmp10p2 + z5p2;
							var z4p2 = 1.306562965 * tmp12p2 + z5p2;
							var z3p2 = tmp11p2 * 0.707106781;
							var z11p2 = tmp7p2 + z3p2;
							var z13p2 = tmp7p2 - z3p2;
							data[dataOff + 40] = z13p2 + z2p2;
							data[dataOff + 24] = z13p2 - z2p2;
							data[dataOff + 8] = z11p2 + z4p2;
							data[dataOff + 56] = z11p2 - z4p2;
							dataOff++;
						}
						var fDCTQuant;
						for(i = 0; i < I64; ++i) {
							fDCTQuant = data[i] * fdtbl[i];
							outputfDCTQuant[i] = (fDCTQuant > 0.0) ? ((fDCTQuant + 0.5) | 0) : ((fDCTQuant - 0.5) | 0);
						}
						return outputfDCTQuant;
					}

					function writeAPP0() {
						writeWord(0xFFE0);
						writeWord(16);
						writeByte(0x4A);
						writeByte(0x46);
						writeByte(0x49);
						writeByte(0x46);
						writeByte(0);
						writeByte(1);
						writeByte(1);
						writeByte(0);
						writeWord(1);
						writeWord(1);
						writeByte(0);
						writeByte(0);
					}

					function writeSOF0(width, height) {
						writeWord(0xFFC0);
						writeWord(17);
						writeByte(8);
						writeWord(height);
						writeWord(width);
						writeByte(3);
						writeByte(1);
						writeByte(0x11);
						writeByte(0);
						writeByte(2);
						writeByte(0x11);
						writeByte(1);
						writeByte(3);
						writeByte(0x11);
						writeByte(1);
					}

					function writeDQT() {
						writeWord(0xFFDB);
						writeWord(132);
						writeByte(0);
						for(var i = 0; i < 64; i++) {
							writeByte(YTable[i]);
						}
						writeByte(1);
						for(var j = 0; j < 64; j++) {
							writeByte(UVTable[j]);
						}
					}

					function writeDHT() {
						writeWord(0xFFC4);
						writeWord(0x01A2);
						writeByte(0);
						for(var i = 0; i < 16; i++) {
							writeByte(std_dc_luminance_nrcodes[i + 1]);
						}
						for(var j = 0; j <= 11; j++) {
							writeByte(std_dc_luminance_values[j]);
						}
						writeByte(0x10);
						for(var k = 0; k < 16; k++) {
							writeByte(std_ac_luminance_nrcodes[k + 1]);
						}
						for(var l = 0; l <= 161; l++) {
							writeByte(std_ac_luminance_values[l]);
						}
						writeByte(1);
						for(var m = 0; m < 16; m++) {
							writeByte(std_dc_chrominance_nrcodes[m + 1]);
						}
						for(var n = 0; n <= 11; n++) {
							writeByte(std_dc_chrominance_values[n]);
						}
						writeByte(0x11);
						for(var o = 0; o < 16; o++) {
							writeByte(std_ac_chrominance_nrcodes[o + 1]);
						}
						for(var p = 0; p <= 161; p++) {
							writeByte(std_ac_chrominance_values[p]);
						}
					}

					function writeSOS() {
						writeWord(0xFFDA);
						writeWord(12);
						writeByte(3);
						writeByte(1);
						writeByte(0);
						writeByte(2);
						writeByte(0x11);
						writeByte(3);
						writeByte(0x11);
						writeByte(0);
						writeByte(0x3f);
						writeByte(0);
					}

					function processDU(CDU, fdtbl, DC, HTDC, HTAC) {
						var EOB = HTAC[0x00];
						var M16zeroes = HTAC[0xF0];
						var pos;
						var I16 = 16;
						var I63 = 63;
						var I64 = 64;
						var DU_DCT = fDCTQuant(CDU, fdtbl);
						for(var j = 0; j < I64; ++j) {
							DU[ZigZag[j]] = DU_DCT[j];
						}
						var Diff = DU[0] - DC;
						DC = DU[0];
						if(Diff == 0) {
							writeBits(HTDC[0]);
						} else {
							pos = 32767 + Diff;
							writeBits(HTDC[category[pos]]);
							writeBits(bitcode[pos]);
						}
						var end0pos = 63;
						for(;
							(end0pos > 0) && (DU[end0pos] == 0); end0pos--) {};
						if(end0pos == 0) {
							writeBits(EOB);
							return DC;
						}
						var i = 1;
						var lng;
						while(i <= end0pos) {
							var startpos = i;
							for(;
								(DU[i] == 0) && (i <= end0pos); ++i) {}
							var nrzeroes = i - startpos;
							if(nrzeroes >= I16) {
								lng = nrzeroes >> 4;
								for(var nrmarker = 1; nrmarker <= lng; ++nrmarker)
									writeBits(M16zeroes);
								nrzeroes = nrzeroes & 0xF;
							}
							pos = 32767 + DU[i];
							writeBits(HTAC[(nrzeroes << 4) + category[pos]]);
							writeBits(bitcode[pos]);
							i++;
						}
						if(end0pos != I63) {
							writeBits(EOB);
						}
						return DC;
					}

					function initCharLookupTable() {
						var sfcc = String.fromCharCode;
						for(var i = 0; i < 256; i++) {
							clt[i] = sfcc(i);
						}
					}
					this.encode = function(image, quality) {
						if(quality) setQuality(quality);
						byteout = new Array();
						bytenew = 0;
						bytepos = 7;
						writeWord(0xFFD8);
						writeAPP0();
						writeDQT();
						writeSOF0(image.width, image.height);
						writeDHT();
						writeSOS();
						var DCY = 0;
						var DCU = 0;
						var DCV = 0;
						bytenew = 0;
						bytepos = 7;
						this.encode.displayName = "_encode_";
						var imageData = image.data;
						var width = image.width;
						var height = image.height;
						var quadWidth = width * 4;
						var tripleWidth = width * 3;
						var x, y = 0;
						var r, g, b;
						var start, p, col, row, pos;
						while(y < height) {
							x = 0;
							while(x < quadWidth) {
								start = quadWidth * y + x;
								p = start;
								col = -1;
								row = 0;
								for(pos = 0; pos < 64; pos++) {
									row = pos >> 3;
									col = (pos & 7) * 4;
									p = start + (row * quadWidth) + col;
									if(y + row >= height) {
										p -= (quadWidth * (y + 1 + row - height));
									}
									if(x + col >= quadWidth) {
										p -= ((x + col) - quadWidth + 4)
									}
									r = imageData[p++];
									g = imageData[p++];
									b = imageData[p++];
									YDU[pos] = ((RGB_YUV_TABLE[r] + RGB_YUV_TABLE[(g + 256) >> 0] + RGB_YUV_TABLE[(b + 512) >> 0]) >> 16) - 128;
									UDU[pos] = ((RGB_YUV_TABLE[(r + 768) >> 0] + RGB_YUV_TABLE[(g + 1024) >> 0] + RGB_YUV_TABLE[(b + 1280) >> 0]) >> 16) - 128;
									VDU[pos] = ((RGB_YUV_TABLE[(r + 1280) >> 0] + RGB_YUV_TABLE[(g + 1536) >> 0] + RGB_YUV_TABLE[(b + 1792) >> 0]) >> 16) - 128;
								}
								DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
								DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
								DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
								x += 32;
							}
							y += 8;
						}
						if(bytepos >= 0) {
							var fillbits = [];
							fillbits[1] = bytepos + 1;
							fillbits[0] = (1 << (bytepos + 1)) - 1;
							writeBits(fillbits);
						}
						writeWord(0xFFD9);
						var jpegDataUri = 'data:image/jpeg;base64,' + btoa(byteout.join(''));
						byteout = [];
						return jpegDataUri
					}

					function setQuality(quality) {
						if(quality <= 0) {
							quality = 1;
						}
						if(quality > 100) {
							quality = 100;
						}
						if(currentQuality == quality) return
						var sf = 0;
						if(quality < 50) {
							sf = Math.floor(5000 / quality);
						} else {
							sf = Math.floor(200 - quality * 2);
						}
						initQuantTables(sf);
						currentQuality = quality;
					}

					function init() {
						if(!quality) quality = 50;
						initCharLookupTable()
						initHuffmanTbl();
						initCategoryNumber();
						initRGBYUVTable();
						setQuality(quality);
					}
					init();
				};
				JPEGEncoder.encode = function(data, quality) {
					var encoder = new JPEGEncoder(quality);
					return encoder.encode(data);
				}
				return JPEGEncoder;
			});
			define('runtime/html5/androidpatch', ['runtime/html5/util', 'runtime/html5/jpegencoder', 'base'], function(Util, encoder, Base) {
				var origin = Util.canvasToDataUrl,
					supportJpeg;
				Util.canvasToDataUrl = function(canvas, type, quality) {
					var ctx, w, h, fragement, parts;
					if(!Base.os.android) {
						return origin.apply(null, arguments);
					}
					if(type === 'image/jpeg' && typeof supportJpeg === 'undefined') {
						fragement = origin.apply(null, arguments);
						parts = fragement.split(',');
						if(~parts[0].indexOf('base64')) {
							fragement = atob(parts[1]);
						} else {
							fragement = decodeURIComponent(parts[1]);
						}
						fragement = fragement.substring(0, 2);
						supportJpeg = fragement.charCodeAt(0) === 255 && fragement.charCodeAt(1) === 216;
					}
					if(type === 'image/jpeg' && !supportJpeg) {
						w = canvas.width;
						h = canvas.height;
						ctx = canvas.getContext('2d');
						return encoder.encode(ctx.getImageData(0, 0, w, h), quality);
					}
					return origin.apply(null, arguments);
				};
			});
			define('runtime/html5/image', ['base', 'runtime/html5/runtime', 'runtime/html5/util'], function(Base, Html5Runtime, Util) {
				var BLANK = '%3D';
				return Html5Runtime.register('Image', {
					modified: false,
					init: function() {
						var me = this,
							img = new Image();
						img.onload = function() {
							me._info = {
								type: me.type,
								width: this.width,
								height: this.height
							};
							if(!me._metas && 'image/jpeg' === me.type) {
								Util.parseMeta(me._blob, function(error, ret) {
									me._metas = ret;
									me.owner.trigger('load');
								});
							} else {
								me.owner.trigger('load');
							}
						};
						img.onerror = function() {
							me.owner.trigger('error');
						};
						me._img = img;
					},
					loadFromBlob: function(blob) {
						var me = this,
							img = me._img;
						me._blob = blob;
						me.type = blob.type;
						img.src = Util.createObjectURL(blob.getSource());
						me.owner.once('load', function() {
							Util.revokeObjectURL(img.src);
						});
					},
					resize: function(width, height) {
						var canvas = this._canvas || (this._canvas = document.createElement('canvas'));
						this._resize(this._img, canvas, width, height);
						this._blob = null;
						this.modified = true;
						this.owner.trigger('complete', 'resize');
					},
					crop: function(x, y, w, h, s) {
						var cvs = this._canvas || (this._canvas = document.createElement('canvas')),
							opts = this.options,
							img = this._img,
							iw = img.naturalWidth,
							ih = img.naturalHeight,
							orientation = this.getOrientation();
						s = s || 1;
						cvs.width = w;
						cvs.height = h;
						opts.preserveHeaders || this._rotate2Orientaion(cvs, orientation);
						this._renderImageToCanvas(cvs, img, -x, -y, iw * s, ih * s);
						this._blob = null;
						this.modified = true;
						this.owner.trigger('complete', 'crop');
					},
					getAsBlob: function(type) {
						var blob = this._blob,
							opts = this.options,
							canvas;
						type = type || this.type;
						if(this.modified || this.type !== type) {
							canvas = this._canvas;
							if(type === 'image/jpeg') {
								blob = Util.canvasToDataUrl(canvas, type, opts.quality);
								if(opts.preserveHeaders && this._metas && this._metas.imageHead) {
									blob = Util.dataURL2ArrayBuffer(blob);
									blob = Util.updateImageHead(blob, this._metas.imageHead);
									blob = Util.arrayBufferToBlob(blob, type);
									return blob;
								}
							} else {
								blob = Util.canvasToDataUrl(canvas, type);
							}
							blob = Util.dataURL2Blob(blob);
						}
						return blob;
					},
					getAsDataUrl: function(type) {
						var opts = this.options;
						type = type || this.type;
						if(type === 'image/jpeg') {
							return Util.canvasToDataUrl(this._canvas, type, opts.quality);
						} else {
							return this._canvas.toDataURL(type);
						}
					},
					getOrientation: function() {
						return this._metas && this._metas.exif && this._metas.exif.get('Orientation') || 1;
					},
					info: function(val) {
						if(val) {
							this._info = val;
							return this;
						}
						return this._info;
					},
					meta: function(val) {
						if(val) {
							this._meta = val;
							return this;
						}
						return this._meta;
					},
					destroy: function() {
						var canvas = this._canvas;
						this._img.onload = null;
						if(canvas) {
							canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height);
							canvas.width = canvas.height = 0;
							this._canvas = null;
						}
						this._img.src = BLANK;
						this._img = this._blob = null;
					},
					_resize: function(img, cvs, width, height) {
						var opts = this.options,
							naturalWidth = img.width,
							naturalHeight = img.height,
							orientation = this.getOrientation(),
							scale, w, h, x, y;
						if(~[5, 6, 7, 8].indexOf(orientation)) {
							width ^= height;
							height ^= width;
							width ^= height;
						}
						scale = Math[opts.crop ? 'max' : 'min'](width / naturalWidth, height / naturalHeight);
						opts.allowMagnify || (scale = Math.min(1, scale));
						w = naturalWidth * scale;
						h = naturalHeight * scale;
						if(opts.crop) {
							cvs.width = width;
							cvs.height = height;
						} else {
							cvs.width = w;
							cvs.height = h;
						}
						x = (cvs.width - w) / 2;
						y = (cvs.height - h) / 2;
						opts.preserveHeaders || this._rotate2Orientaion(cvs, orientation);
						this._renderImageToCanvas(cvs, img, x, y, w, h);
					},
					_rotate2Orientaion: function(canvas, orientation) {
						var width = canvas.width,
							height = canvas.height,
							ctx = canvas.getContext('2d');
						switch(orientation) {
							case 5:
							case 6:
							case 7:
							case 8:
								canvas.width = height;
								canvas.height = width;
								break;
						}
						switch(orientation) {
							case 2:
								ctx.translate(width, 0);
								ctx.scale(-1, 1);
								break;
							case 3:
								ctx.translate(width, height);
								ctx.rotate(Math.PI);
								break;
							case 4:
								ctx.translate(0, height);
								ctx.scale(1, -1);
								break;
							case 5:
								ctx.rotate(0.5 * Math.PI);
								ctx.scale(1, -1);
								break;
							case 6:
								ctx.rotate(0.5 * Math.PI);
								ctx.translate(0, -height);
								break;
							case 7:
								ctx.rotate(0.5 * Math.PI);
								ctx.translate(width, -height);
								ctx.scale(-1, 1);
								break;
							case 8:
								ctx.rotate(-0.5 * Math.PI);
								ctx.translate(-width, 0);
								break;
						}
					},
					_renderImageToCanvas: (function() {
						if(!Base.os.ios) {
							return function(canvas) {
								var args = Base.slice(arguments, 1),
									ctx = canvas.getContext('2d');
								ctx.drawImage.apply(ctx, args);
							};
						}

						function detectVerticalSquash(img, iw, ih) {
							var canvas = document.createElement('canvas'),
								ctx = canvas.getContext('2d'),
								sy = 0,
								ey = ih,
								py = ih,
								data, alpha, ratio;
							canvas.width = 1;
							canvas.height = ih;
							ctx.drawImage(img, 0, 0);
							data = ctx.getImageData(0, 0, 1, ih).data;
							while(py > sy) {
								alpha = data[(py - 1) * 4 + 3];
								if(alpha === 0) {
									ey = py;
								} else {
									sy = py;
								}
								py = (ey + sy) >> 1;
							}
							ratio = (py / ih);
							return(ratio === 0) ? 1 : ratio;
						}
						if(Base.os.ios >= 7) {
							return function(canvas, img, x, y, w, h) {
								var iw = img.naturalWidth,
									ih = img.naturalHeight,
									vertSquashRatio = detectVerticalSquash(img, iw, ih);
								return canvas.getContext('2d').drawImage(img, 0, 0, iw * vertSquashRatio, ih * vertSquashRatio, x, y, w, h);
							};
						}

						function detectSubsampling(img) {
							var iw = img.naturalWidth,
								ih = img.naturalHeight,
								canvas, ctx;
							if(iw * ih > 1024 * 1024) {
								canvas = document.createElement('canvas');
								canvas.width = canvas.height = 1;
								ctx = canvas.getContext('2d');
								ctx.drawImage(img, -iw + 1, 0);
								return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
							} else {
								return false;
							}
						}
						return function(canvas, img, x, y, width, height) {
							var iw = img.naturalWidth,
								ih = img.naturalHeight,
								ctx = canvas.getContext('2d'),
								subsampled = detectSubsampling(img),
								doSquash = this.type === 'image/jpeg',
								d = 1024,
								sy = 0,
								dy = 0,
								tmpCanvas, tmpCtx, vertSquashRatio, dw, dh, sx, dx;
							if(subsampled) {
								iw /= 2;
								ih /= 2;
							}
							ctx.save();
							tmpCanvas = document.createElement('canvas');
							tmpCanvas.width = tmpCanvas.height = d;
							tmpCtx = tmpCanvas.getContext('2d');
							vertSquashRatio = doSquash ? detectVerticalSquash(img, iw, ih) : 1;
							dw = Math.ceil(d * width / iw);
							dh = Math.ceil(d * height / ih / vertSquashRatio);
							while(sy < ih) {
								sx = 0;
								dx = 0;
								while(sx < iw) {
									tmpCtx.clearRect(0, 0, d, d);
									tmpCtx.drawImage(img, -sx, -sy);
									ctx.drawImage(tmpCanvas, 0, 0, d, d, x + dx, y + dy, dw, dh);
									sx += d;
									dx += dw;
								}
								sy += d;
								dy += dh;
							}
							ctx.restore();
							tmpCanvas = tmpCtx = null;
						};
					})()
				});
			});
			define('runtime/html5/transport', ['base', 'runtime/html5/runtime'], function(Base, Html5Runtime) {
				var noop = Base.noop,
					$ = Base.$;
				return Html5Runtime.register('Transport', {
					init: function() {
						this._status = 0;
						this._response = null;
					},
					send: function() {
						var owner = this.owner,
							opts = this.options,
							xhr = this._initAjax(),
							blob = owner._blob,
							server = opts.server,
							formData, binary, fr;
						if(opts.sendAsBinary) {
							server += (/\?/.test(server) ? '&' : '?') +
								$.param(owner._formData);
							binary = blob.getSource();
						} else {
							formData = new FormData();
							$.each(owner._formData, function(k, v) {
								formData.append(k, v);
							});
							formData.append(opts.fileVal, blob.getSource(), opts.filename || owner._formData.name || '');
						}
						if(opts.withCredentials && 'withCredentials' in xhr) {
							xhr.open(opts.method, server, true);
							xhr.withCredentials = true;
						} else {
							xhr.open(opts.method, server);
						}
						this._setRequestHeader(xhr, opts.headers);
						if(binary) {
							xhr.overrideMimeType && xhr.overrideMimeType('application/octet-stream');
							if(Base.os.android) {
								fr = new FileReader();
								fr.onload = function() {
									xhr.send(this.result);
									fr = fr.onload = null;
								};
								fr.readAsArrayBuffer(binary);
							} else {
								xhr.send(binary);
							}
						} else {
							xhr.send(formData);
						}
					},
					getResponse: function() {
						return this._response;
					},
					getResponseAsJson: function() {
						return this._parseJson(this._response);
					},
					getStatus: function() {
						return this._status;
					},
					abort: function() {
						var xhr = this._xhr;
						if(xhr) {
							xhr.upload.onprogress = noop;
							xhr.onreadystatechange = noop;
							xhr.abort();
							this._xhr = xhr = null;
						}
					},
					destroy: function() {
						this.abort();
					},
					_initAjax: function() {
						var me = this,
							xhr = new XMLHttpRequest(),
							opts = this.options;
						if(opts.withCredentials && !('withCredentials' in xhr) && typeof XDomainRequest !== 'undefined') {
							xhr = new XDomainRequest();
						}
						xhr.upload.onprogress = function(e) {
							var percentage = 0;
							if(e.lengthComputable) {
								percentage = e.loaded / e.total;
							}
							return me.trigger('progress', percentage);
						};
						xhr.onreadystatechange = function() {
							if(xhr.readyState !== 4) {
								return;
							}
							xhr.upload.onprogress = noop;
							xhr.onreadystatechange = noop;
							me._xhr = null;
							me._status = xhr.status;
							if(xhr.status >= 200 && xhr.status < 300) {
								me._response = xhr.responseText;
								return me.trigger('load');
							} else if(xhr.status >= 500 && xhr.status < 600) {
								me._response = xhr.responseText;
								return me.trigger('error', 'server');
							}
							return me.trigger('error', me._status ? 'http' : 'abort');
						};
						me._xhr = xhr;
						return xhr;
					},
					_setRequestHeader: function(xhr, headers) {
						$.each(headers, function(key, val) {
							xhr.setRequestHeader(key, val);
						});
					},
					_parseJson: function(str) {
						var json;
						try {
							json = JSON.parse(str);
						} catch(ex) {
							json = {};
						}
						return json;
					}
				});
			});
			define('runtime/html5/md5', ['runtime/html5/runtime'], function(FlashRuntime) {
				var add32 = function(a, b) {
						return(a + b) & 0xFFFFFFFF;
					},
					cmn = function(q, a, b, x, s, t) {
						a = add32(add32(a, q), add32(x, t));
						return add32((a << s) | (a >>> (32 - s)), b);
					},
					ff = function(a, b, c, d, x, s, t) {
						return cmn((b & c) | ((~b) & d), a, b, x, s, t);
					},
					gg = function(a, b, c, d, x, s, t) {
						return cmn((b & d) | (c & (~d)), a, b, x, s, t);
					},
					hh = function(a, b, c, d, x, s, t) {
						return cmn(b ^ c ^ d, a, b, x, s, t);
					},
					ii = function(a, b, c, d, x, s, t) {
						return cmn(c ^ (b | (~d)), a, b, x, s, t);
					},
					md5cycle = function(x, k) {
						var a = x[0],
							b = x[1],
							c = x[2],
							d = x[3];
						a = ff(a, b, c, d, k[0], 7, -680876936);
						d = ff(d, a, b, c, k[1], 12, -389564586);
						c = ff(c, d, a, b, k[2], 17, 606105819);
						b = ff(b, c, d, a, k[3], 22, -1044525330);
						a = ff(a, b, c, d, k[4], 7, -176418897);
						d = ff(d, a, b, c, k[5], 12, 1200080426);
						c = ff(c, d, a, b, k[6], 17, -1473231341);
						b = ff(b, c, d, a, k[7], 22, -45705983);
						a = ff(a, b, c, d, k[8], 7, 1770035416);
						d = ff(d, a, b, c, k[9], 12, -1958414417);
						c = ff(c, d, a, b, k[10], 17, -42063);
						b = ff(b, c, d, a, k[11], 22, -1990404162);
						a = ff(a, b, c, d, k[12], 7, 1804603682);
						d = ff(d, a, b, c, k[13], 12, -40341101);
						c = ff(c, d, a, b, k[14], 17, -1502002290);
						b = ff(b, c, d, a, k[15], 22, 1236535329);
						a = gg(a, b, c, d, k[1], 5, -165796510);
						d = gg(d, a, b, c, k[6], 9, -1069501632);
						c = gg(c, d, a, b, k[11], 14, 643717713);
						b = gg(b, c, d, a, k[0], 20, -373897302);
						a = gg(a, b, c, d, k[5], 5, -701558691);
						d = gg(d, a, b, c, k[10], 9, 38016083);
						c = gg(c, d, a, b, k[15], 14, -660478335);
						b = gg(b, c, d, a, k[4], 20, -405537848);
						a = gg(a, b, c, d, k[9], 5, 568446438);
						d = gg(d, a, b, c, k[14], 9, -1019803690);
						c = gg(c, d, a, b, k[3], 14, -187363961);
						b = gg(b, c, d, a, k[8], 20, 1163531501);
						a = gg(a, b, c, d, k[13], 5, -1444681467);
						d = gg(d, a, b, c, k[2], 9, -51403784);
						c = gg(c, d, a, b, k[7], 14, 1735328473);
						b = gg(b, c, d, a, k[12], 20, -1926607734);
						a = hh(a, b, c, d, k[5], 4, -378558);
						d = hh(d, a, b, c, k[8], 11, -2022574463);
						c = hh(c, d, a, b, k[11], 16, 1839030562);
						b = hh(b, c, d, a, k[14], 23, -35309556);
						a = hh(a, b, c, d, k[1], 4, -1530992060);
						d = hh(d, a, b, c, k[4], 11, 1272893353);
						c = hh(c, d, a, b, k[7], 16, -155497632);
						b = hh(b, c, d, a, k[10], 23, -1094730640);
						a = hh(a, b, c, d, k[13], 4, 681279174);
						d = hh(d, a, b, c, k[0], 11, -358537222);
						c = hh(c, d, a, b, k[3], 16, -722521979);
						b = hh(b, c, d, a, k[6], 23, 76029189);
						a = hh(a, b, c, d, k[9], 4, -640364487);
						d = hh(d, a, b, c, k[12], 11, -421815835);
						c = hh(c, d, a, b, k[15], 16, 530742520);
						b = hh(b, c, d, a, k[2], 23, -995338651);
						a = ii(a, b, c, d, k[0], 6, -198630844);
						d = ii(d, a, b, c, k[7], 10, 1126891415);
						c = ii(c, d, a, b, k[14], 15, -1416354905);
						b = ii(b, c, d, a, k[5], 21, -57434055);
						a = ii(a, b, c, d, k[12], 6, 1700485571);
						d = ii(d, a, b, c, k[3], 10, -1894986606);
						c = ii(c, d, a, b, k[10], 15, -1051523);
						b = ii(b, c, d, a, k[1], 21, -2054922799);
						a = ii(a, b, c, d, k[8], 6, 1873313359);
						d = ii(d, a, b, c, k[15], 10, -30611744);
						c = ii(c, d, a, b, k[6], 15, -1560198380);
						b = ii(b, c, d, a, k[13], 21, 1309151649);
						a = ii(a, b, c, d, k[4], 6, -145523070);
						d = ii(d, a, b, c, k[11], 10, -1120210379);
						c = ii(c, d, a, b, k[2], 15, 718787259);
						b = ii(b, c, d, a, k[9], 21, -343485551);
						x[0] = add32(a, x[0]);
						x[1] = add32(b, x[1]);
						x[2] = add32(c, x[2]);
						x[3] = add32(d, x[3]);
					},
					md5blk = function(s) {
						var md5blks = [],
							i;
						for(i = 0; i < 64; i += 4) {
							md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s.charCodeAt(i + 3) << 24);
						}
						return md5blks;
					},
					md5blk_array = function(a) {
						var md5blks = [],
							i;
						for(i = 0; i < 64; i += 4) {
							md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
						}
						return md5blks;
					},
					md51 = function(s) {
						var n = s.length,
							state = [1732584193, -271733879, -1732584194, 271733878],
							i, length, tail, tmp, lo, hi;
						for(i = 64; i <= n; i += 64) {
							md5cycle(state, md5blk(s.substring(i - 64, i)));
						}
						s = s.substring(i - 64);
						length = s.length;
						tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
						for(i = 0; i < length; i += 1) {
							tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
						}
						tail[i >> 2] |= 0x80 << ((i % 4) << 3);
						if(i > 55) {
							md5cycle(state, tail);
							for(i = 0; i < 16; i += 1) {
								tail[i] = 0;
							}
						}
						tmp = n * 8;
						tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
						lo = parseInt(tmp[2], 16);
						hi = parseInt(tmp[1], 16) || 0;
						tail[14] = lo;
						tail[15] = hi;
						md5cycle(state, tail);
						return state;
					},
					md51_array = function(a) {
						var n = a.length,
							state = [1732584193, -271733879, -1732584194, 271733878],
							i, length, tail, tmp, lo, hi;
						for(i = 64; i <= n; i += 64) {
							md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
						}
						a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);
						length = a.length;
						tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
						for(i = 0; i < length; i += 1) {
							tail[i >> 2] |= a[i] << ((i % 4) << 3);
						}
						tail[i >> 2] |= 0x80 << ((i % 4) << 3);
						if(i > 55) {
							md5cycle(state, tail);
							for(i = 0; i < 16; i += 1) {
								tail[i] = 0;
							}
						}
						tmp = n * 8;
						tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
						lo = parseInt(tmp[2], 16);
						hi = parseInt(tmp[1], 16) || 0;
						tail[14] = lo;
						tail[15] = hi;
						md5cycle(state, tail);
						return state;
					},
					hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'],
					rhex = function(n) {
						var s = '',
							j;
						for(j = 0; j < 4; j += 1) {
							s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
						}
						return s;
					},
					hex = function(x) {
						var i;
						for(i = 0; i < x.length; i += 1) {
							x[i] = rhex(x[i]);
						}
						return x.join('');
					},
					md5 = function(s) {
						return hex(md51(s));
					},
					SparkMD5 = function() {
						this.reset();
					};
				if(md5('hello') !== '5d41402abc4b2a76b9719d911017c592') {
					add32 = function(x, y) {
						var lsw = (x & 0xFFFF) + (y & 0xFFFF),
							msw = (x >> 16) + (y >> 16) + (lsw >> 16);
						return(msw << 16) | (lsw & 0xFFFF);
					};
				}
				SparkMD5.prototype.append = function(str) {
					if(/[\u0080-\uFFFF]/.test(str)) {
						str = unescape(encodeURIComponent(str));
					}
					this.appendBinary(str);
					return this;
				};
				SparkMD5.prototype.appendBinary = function(contents) {
					this._buff += contents;
					this._length += contents.length;
					var length = this._buff.length,
						i;
					for(i = 64; i <= length; i += 64) {
						md5cycle(this._state, md5blk(this._buff.substring(i - 64, i)));
					}
					this._buff = this._buff.substr(i - 64);
					return this;
				};
				SparkMD5.prototype.end = function(raw) {
					var buff = this._buff,
						length = buff.length,
						i, tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						ret;
					for(i = 0; i < length; i += 1) {
						tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
					}
					this._finish(tail, length);
					ret = !!raw ? this._state : hex(this._state);
					this.reset();
					return ret;
				};
				SparkMD5.prototype._finish = function(tail, length) {
					var i = length,
						tmp, lo, hi;
					tail[i >> 2] |= 0x80 << ((i % 4) << 3);
					if(i > 55) {
						md5cycle(this._state, tail);
						for(i = 0; i < 16; i += 1) {
							tail[i] = 0;
						}
					}
					tmp = this._length * 8;
					tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
					lo = parseInt(tmp[2], 16);
					hi = parseInt(tmp[1], 16) || 0;
					tail[14] = lo;
					tail[15] = hi;
					md5cycle(this._state, tail);
				};
				SparkMD5.prototype.reset = function() {
					this._buff = "";
					this._length = 0;
					this._state = [1732584193, -271733879, -1732584194, 271733878];
					return this;
				};
				SparkMD5.prototype.destroy = function() {
					delete this._state;
					delete this._buff;
					delete this._length;
				};
				SparkMD5.hash = function(str, raw) {
					if(/[\u0080-\uFFFF]/.test(str)) {
						str = unescape(encodeURIComponent(str));
					}
					var hash = md51(str);
					return !!raw ? hash : hex(hash);
				};
				SparkMD5.hashBinary = function(content, raw) {
					var hash = md51(content);
					return !!raw ? hash : hex(hash);
				};
				SparkMD5.ArrayBuffer = function() {
					this.reset();
				};
				SparkMD5.ArrayBuffer.prototype.append = function(arr) {
					var buff = this._concatArrayBuffer(this._buff, arr),
						length = buff.length,
						i;
					this._length += arr.byteLength;
					for(i = 64; i <= length; i += 64) {
						md5cycle(this._state, md5blk_array(buff.subarray(i - 64, i)));
					}
					this._buff = (i - 64) < length ? buff.subarray(i - 64) : new Uint8Array(0);
					return this;
				};
				SparkMD5.ArrayBuffer.prototype.end = function(raw) {
					var buff = this._buff,
						length = buff.length,
						tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
						i, ret;
					for(i = 0; i < length; i += 1) {
						tail[i >> 2] |= buff[i] << ((i % 4) << 3);
					}
					this._finish(tail, length);
					ret = !!raw ? this._state : hex(this._state);
					this.reset();
					return ret;
				};
				SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;
				SparkMD5.ArrayBuffer.prototype.reset = function() {
					this._buff = new Uint8Array(0);
					this._length = 0;
					this._state = [1732584193, -271733879, -1732584194, 271733878];
					return this;
				};
				SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;
				SparkMD5.ArrayBuffer.prototype._concatArrayBuffer = function(first, second) {
					var firstLength = first.length,
						result = new Uint8Array(firstLength + second.byteLength);
					result.set(first);
					result.set(new Uint8Array(second), firstLength);
					return result;
				};
				SparkMD5.ArrayBuffer.hash = function(arr, raw) {
					var hash = md51_array(new Uint8Array(arr));
					return !!raw ? hash : hex(hash);
				};
				return FlashRuntime.register('Md5', {
					init: function() {},
					loadFromBlob: function(file) {
						var blob = file.getSource(),
							chunkSize = 2 * 1024 * 1024,
							chunks = Math.ceil(blob.size / chunkSize),
							chunk = 0,
							owner = this.owner,
							spark = new SparkMD5.ArrayBuffer(),
							me = this,
							blobSlice = blob.mozSlice || blob.webkitSlice || blob.slice,
							loadNext, fr;
						fr = new FileReader();
						loadNext = function() {
							var start, end;
							start = chunk * chunkSize;
							end = Math.min(start + chunkSize, blob.size);
							fr.onload = function(e) {
								spark.append(e.target.result);
								owner.trigger('progress', {
									total: file.size,
									loaded: end
								});
							};
							fr.onloadend = function() {
								fr.onloadend = fr.onload = null;
								if(++chunk < chunks) {
									setTimeout(loadNext, 1);
								} else {
									setTimeout(function() {
										owner.trigger('load');
										me.result = spark.end();
										loadNext = file = blob = spark = null;
										owner.trigger('complete');
									}, 50);
								}
							};
							fr.readAsArrayBuffer(blobSlice.call(blob, start, end));
						};
						loadNext();
					},
					getResult: function() {
						return this.result;
					}
				});
			});
			define('runtime/flash/runtime', ['base', 'runtime/runtime', 'runtime/compbase'], function(Base, Runtime, CompBase) {
				var $ = Base.$,
					type = 'flash',
					components = {};

				function getFlashVersion() {
					var version;
					try {
						version = navigator.plugins['Shockwave Flash'];
						version = version.description;
					} catch(ex) {
						try {
							version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
						} catch(ex2) {
							version = '0.0';
						}
					}
					version = version.match(/\d+/g);
					return parseFloat(version[0] + '.' + version[1], 10);
				}

				function FlashRuntime() {
					var pool = {},
						clients = {},
						destroy = this.destroy,
						me = this,
						jsreciver = Base.guid('webuploader_');
					Runtime.apply(me, arguments);
					me.type = type;
					me.exec = function(comp, fn) {
						var client = this,
							uid = client.uid,
							args = Base.slice(arguments, 2),
							instance;
						clients[uid] = client;
						if(components[comp]) {
							if(!pool[uid]) {
								pool[uid] = new components[comp](client, me);
							}
							instance = pool[uid];
							if(instance[fn]) {
								return instance[fn].apply(instance, args);
							}
						}
						return me.flashExec.apply(client, arguments);
					};

					function handler(evt, obj) {
						var type = evt.type || evt,
							parts, uid;
						parts = type.split('::');
						uid = parts[0];
						type = parts[1];
						if(type === 'Ready' && uid === me.uid) {
							me.trigger('ready');
						} else if(clients[uid]) {
							clients[uid].trigger(type.toLowerCase(), evt, obj);
						}
					}
					window[jsreciver] = function() {
						var args = arguments;
						setTimeout(function() {
							handler.apply(null, args);
						}, 1);
					};
					this.jsreciver = jsreciver;
					this.destroy = function() {
						return destroy && destroy.apply(this, arguments);
					};
					this.flashExec = function(comp, fn) {
						var flash = me.getFlash(),
							args = Base.slice(arguments, 2);
						return flash.exec(this.uid, comp, fn, args);
					};
				}
				Base.inherits(Runtime, {
					constructor: FlashRuntime,
					init: function() {
						var container = this.getContainer(),
							opts = this.options,
							html;
						container.css({
							position: 'absolute',
							top: '-8px',
							left: '-8px',
							width: '9px',
							height: '9px',
							overflow: 'hidden'
						});
						html = '<object id="' + this.uid + '" type="application/' +
							'x-shockwave-flash" data="' + opts.swf + '" ';
						if(Base.browser.ie) {
							html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
						}
						html += 'width="100%" height="100%" style="outline:0">' +
							'<param name="movie" value="' + opts.swf + '" />' +
							'<param name="flashvars" value="uid=' + this.uid +
							'&jsreciver=' + this.jsreciver + '" />' +
							'<param name="wmode" value="transparent" />' +
							'<param name="allowscriptaccess" value="always" />' +
							'</object>';
						container.html(html);
					},
					getFlash: function() {
						if(this._flash) {
							return this._flash;
						}
						this._flash = $('#' + this.uid).get(0);
						return this._flash;
					}
				});
				FlashRuntime.register = function(name, component) {
					component = components[name] = Base.inherits(CompBase, $.extend({
						flashExec: function() {
							var owner = this.owner,
								runtime = this.getRuntime();
							return runtime.flashExec.apply(owner, arguments);
						}
					}, component));
					return component;
				};
				if(getFlashVersion() >= 11.4) {
					Runtime.addRuntime(type, FlashRuntime);
				}
				return FlashRuntime;
			});
			define('runtime/flash/filepicker', ['base', 'runtime/flash/runtime'], function(Base, FlashRuntime) {
				var $ = Base.$;
				return FlashRuntime.register('FilePicker', {
					init: function(opts) {
						var copy = $.extend({}, opts),
							len, i;
						len = copy.accept && copy.accept.length;
						for(i = 0; i < len; i++) {
							if(!copy.accept[i].title) {
								copy.accept[i].title = 'Files';
							}
						}
						delete copy.button;
						delete copy.id;
						delete copy.container;
						this.flashExec('FilePicker', 'init', copy);
					},
					destroy: function() {
						this.flashExec('FilePicker', 'destroy');
					}
				});
			});
			define('runtime/flash/image', ['runtime/flash/runtime'], function(FlashRuntime) {
				return FlashRuntime.register('Image', {
					loadFromBlob: function(blob) {
						var owner = this.owner;
						owner.info() && this.flashExec('Image', 'info', owner.info());
						owner.meta() && this.flashExec('Image', 'meta', owner.meta());
						this.flashExec('Image', 'loadFromBlob', blob.uid);
					}
				});
			});
			define('runtime/flash/transport', ['base', 'runtime/flash/runtime', 'runtime/client'], function(Base, FlashRuntime, RuntimeClient) {
				var $ = Base.$;
				return FlashRuntime.register('Transport', {
					init: function() {
						this._status = 0;
						this._response = null;
						this._responseJson = null;
					},
					send: function() {
						var owner = this.owner,
							opts = this.options,
							xhr = this._initAjax(),
							blob = owner._blob,
							server = opts.server,
							binary;
						xhr.connectRuntime(blob.ruid);
						if(opts.sendAsBinary) {
							server += (/\?/.test(server) ? '&' : '?') +
								$.param(owner._formData);
							binary = blob.uid;
						} else {
							$.each(owner._formData, function(k, v) {
								xhr.exec('append', k, v);
							});
							xhr.exec('appendBlob', opts.fileVal, blob.uid, opts.filename || owner._formData.name || '');
						}
						this._setRequestHeader(xhr, opts.headers);
						xhr.exec('send', {
							method: opts.method,
							url: server,
							forceURLStream: opts.forceURLStream,
							mimeType: 'application/octet-stream'
						}, binary);
					},
					getStatus: function() {
						return this._status;
					},
					getResponse: function() {
						return this._response || '';
					},
					getResponseAsJson: function() {
						return this._responseJson;
					},
					abort: function() {
						var xhr = this._xhr;
						if(xhr) {
							xhr.exec('abort');
							xhr.destroy();
							this._xhr = xhr = null;
						}
					},
					destroy: function() {
						this.abort();
					},
					_initAjax: function() {
						var me = this,
							xhr = new RuntimeClient('XMLHttpRequest');
						xhr.on('uploadprogress progress', function(e) {
							var percent = e.loaded / e.total;
							percent = Math.min(1, Math.max(0, percent));
							return me.trigger('progress', percent);
						});
						xhr.on('load', function() {
							var status = xhr.exec('getStatus'),
								readBody = false,
								err = '',
								p;
							xhr.off();
							me._xhr = null;
							if(status >= 200 && status < 300) {
								readBody = true;
							} else if(status >= 500 && status < 600) {
								readBody = true;
								err = 'server';
							} else {
								err = 'http';
							}
							if(readBody) {
								me._response = xhr.exec('getResponse');
								me._response = decodeURIComponent(me._response);
								p = window.JSON && window.JSON.parse || function(s) {
									try {
										return new Function('return ' + s).call();
									} catch(err) {
										return {};
									}
								};
								me._responseJson = me._response ? p(me._response) : {};
							}
							xhr.destroy();
							xhr = null;
							return err ? me.trigger('error', err) : me.trigger('load');
						});
						xhr.on('error', function() {
							xhr.off();
							me._xhr = null;
							me.trigger('error', 'http');
						});
						me._xhr = xhr;
						return xhr;
					},
					_setRequestHeader: function(xhr, headers) {
						$.each(headers, function(key, val) {
							xhr.exec('setRequestHeader', key, val);
						});
					}
				});
			});
			define('runtime/flash/blob', ['runtime/flash/runtime', 'lib/blob'], function(FlashRuntime, Blob) {
				return FlashRuntime.register('Blob', {
					slice: function(start, end) {
						var blob = this.flashExec('Blob', 'slice', start, end);
						return new Blob(blob.uid, blob);
					}
				});
			});
			define('runtime/flash/md5', ['runtime/flash/runtime'], function(FlashRuntime) {
				return FlashRuntime.register('Md5', {
					init: function() {},
					loadFromBlob: function(blob) {
						return this.flashExec('Md5', 'loadFromBlob', blob.uid);
					}
				});
			});
			define('preset/all', ['base', 'widgets/filednd', 'widgets/filepaste', 'widgets/filepicker', 'widgets/image', 'widgets/queue', 'widgets/runtime', 'widgets/upload', 'widgets/validator', 'widgets/md5', 'runtime/html5/blob', 'runtime/html5/dnd', 'runtime/html5/filepaste', 'runtime/html5/filepicker', 'runtime/html5/imagemeta/exif', 'runtime/html5/androidpatch', 'runtime/html5/image', 'runtime/html5/transport', 'runtime/html5/md5', 'runtime/flash/filepicker', 'runtime/flash/image', 'runtime/flash/transport', 'runtime/flash/blob', 'runtime/flash/md5'], function(Base) {
				return Base;
			});
			define('widgets/log', ['base', 'uploader', 'widgets/widget'], function(Base, Uploader) {
				var $ = Base.$,
					logUrl = ' http://static.tieba.baidu.com/tb/pms/img/st.gif??',
					product = (location.hostname || location.host || 'protected').toLowerCase(),
					enable = product && /baidu/i.exec(product),
					base;
				if(!enable) {
					return;
				}
				base = {
					dv: 3,
					master: 'webuploader',
					online: /test/.exec(product) ? 0 : 1,
					module: '',
					product: product,
					type: 0
				};

				function send(data) {
					var obj = $.extend({}, base, data),
						url = logUrl.replace(/^(.*)\?/, '$1' + $.param(obj)),
						image = new Image();
					image.src = url;
				}
				return Uploader.register({
					name: 'log',
					init: function() {
						var owner = this.owner,
							count = 0,
							size = 0;
						owner.on('error', function(code) {
							send({
								type: 2,
								c_error_code: code
							});
						}).on('uploadError', function(file, reason) {
							send({
								type: 2,
								c_error_code: 'UPLOAD_ERROR',
								c_reason: '' + reason
							});
						}).on('uploadComplete', function(file) {
							count++;
							size += file.size;
						}).on('uploadFinished', function() {
							send({
								c_count: count,
								c_size: size
							});
							count = size = 0;
						});
						send({
							c_usage: 1
						});
					}
				});
			});
			define('webuploader', ['preset/all', 'widgets/log'], function(preset) {
				return preset;
			});
			return require('webuploader');
		});
	})(jQuery);
	layui.link(basePath + '../../lib/layui/lay/modules/webuploader/webuploader.css');
	exports('webuploader', null);
});